题目链接:
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 ;
}