UVA 11997 STL 优先队列

时间:2023-03-09 04:09:57
UVA 11997 STL 优先队列

题目链接:

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3148

题意:给K个数组,每个数组含有K个整数,从每个数组中各选一个数加起来,得到一个sum,这样的选法一共有K^k种,现在求这样的和中最小的K个sum.

解法:先考虑两个数组的情形

假设A1<=A2<=`````<=AK

B1<=B2<=`````<=Bk

则有

A1+B1<=A1+B2<=`````<=A1+Bk.

A2+B1<=A2+B2<=`````<=A2+Bk.

```````

Ak+B1<=Ak+B2<=`````<=Ak+Bk.

首先把第一列的数<s[i] = A[i] + B[1]     ,      1>,第一个数为和,第二个数为B的序号,放入优先队列,然后从优先队列中弹出最小的,这个最小值一定是所有和中最小的,同时压入A[a] + B[b+1],A[a]+B[b+1] = s-B[b]+B[b+1]....这样循环n次即可。得到了n个最小和。因为这里有k个数组,两两合并即可。

以上摘自刘汝佳的大白书190页。(是看了他的书写的,如果有错了不是他写错了,必然是我写错了)

贴代码:

 #include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
#define N 755
int k[N][N],n;
struct Item
{
int s,b;//s = A[a] + B[b]
Item(int s,int b):s(s),b(b) {}
bool operator<(const Item & other)const
{
return s > other.s;
}
};
void output(int a[])
{
printf("array :\n");
for(int i=; i<n; ++i)
printf("%d ",a[i]);
puts("");
}
void combine(int A[],int B[])
{
priority_queue<Item> q;
for(int i =; i<n; ++i)
q.push(Item(A[i]+B[] , ));
for(int i=; i<n; ++i)
{
Item item = q.top();
q.pop();
A[i] = item.s;
int b = item.b;
if(b+ < n ) q.push(Item(item.s - B[b] + B[b+] , b+));
}
}
int main()
{
// freopen("in.txt","r",stdin);
while(~scanf("%d",&n))
{
for(int i=; i<n; ++i)
{
for(int j=; j<n; ++j)
scanf("%d",&k[i][j]);
sort(k[i],k[i]+n);
}
for(int i=; i<n; ++i)
combine(k[],k[i]);
printf("%d",k[][]);
for(int i=; i < n; ++i)
printf(" %d",k[][i]);
puts("");
}
return ;
}