题目:
You're given k arrays, each array has k integers. There are kk ways to pick exactly one element in each array and calculate the sum of the integers. Your task is to find the k smallest sums among them.
Input
There will be several test cases. The first line of each case contains an integer k (2<=k<=750). Each of the following k lines contains k positive integers in each array. Each of these integers does not exceed 1,000,000. The input is terminated by end-of-file (EOF). The size of input file does not exceed 5MB.
Output
For each test case, print the k smallest sums, in ascending order.
Sample Input
3
1 8 5
9 2 5
10 7 6
2
1 1
1 2
Output for the Sample Input
9 10 12
2 2
题目是要你求k 个数组。由这些数组每个都取出一个数字,可以组成K的K次方的排列组合出来 。
求其中最小的K个值。
要用到优先队列。
我从白皮书上看到这道题目的时候,也是看不懂。后面明白了。
首先求这些数组的最小和的时候,要先排序,排序之后,你才知道你加入优先队列的数是当前
的最小值,除了优先队列的数,先筛选出优先队列的最小值。
其中这个公式比较关键:S=Aa+Bb;
那么下个添加的数字一定是S'=Aa+Bb+1=Aa+Bb-Bb+Bb+1=S-Bb+Bb+1;
至于为什么是这个,你可以将排好序的两组数进行手动的计算一下,就会发现的确如此。
这里也就是只要用到B数组的下标的原因。
#include<stdio.h>
#include<algorithm>
#include<queue>
using namespace std;
int n;
const int maxn=768;
int A[maxn],B[maxn];
struct Item{
int s,b;
Item(int s,int b):s(s),b(b){}
bool operator<(const Item & C)const
{
return s>C.s;
}
};
void merge()
{
priority_queue<Item> q;
for(int i=0;i<n;i++){
q.push(Item(A[i]+B[0],0));
}
for(int i=0;i<n;i++){
Item item=q.top();
q.pop();
A[i]=item.s;
int b=item.b;
if(b+1<n)q.push(Item(item.s-B[b]+B[b+1],b+1));
}
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i<n;i++){
for(int j=0;j<n;j++)
if(i==0) scanf("%d",&A[j]);
else scanf("%d",&B[j]);
if(i==0) sort(A,A+n);
else sort(B,B+n);
if(i>0)
merge();
}
for(int i=0;i<n;i++)
printf("%d%c",A[i],i==n-1?'\n':' ');
}
return 0;
}