You’re given k arrays, each array has k integers. There are k
k 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).
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
Sample Output
9 10 12
2 2
题目大意:
给定n组数组,每组数组有n个元素,每个数组取一个元素一共有n的n次方种组合,问哪种组合使得他们的和最小,输出n种组合的最小和(递增输出)。
思路:先将每组数据排序,然后再归并求最小和。
因为每个数组第一个元素都是最小值,所以组合起来也是最小值,然后归并起来,再用这个思路去做就可以了。这里用到了优先队列的自动排序。
代码:
#include<iostream>
#include<queue>
#include<bits/stdc++.h>
#include<algorithm>
#define MAXN 750
using namespace std;
int a[MAXN][MAXN];
struct node
{
int sum;//这个用的秒
int coordinate;
node(int sum,int coordinate):sum(sum),coordinate(coordinate){
}
bool operator<(const node &a)const{
return sum>a.sum;
}
};
void merge(int *a,int *b,int *c,int n)
{
priority_queue<node>pp;
for(int i=0;i<n;i++){//因为数组a和b都已经排序过了,所以可以保证
//push的第一一个元素一定是当前最小值,0代表b数组元素的下标,都是从0开始
pp.push(node(a[i]+b[0],0));
}
for(int i=0;i<n;i++){//优先队列的top都是最小值
node q=pp.top();
pp.pop();
c[i]=q.sum;
int bb=q.coordinate;
if(bb+1<n){//保证测试到b数组中最后一个数据之前
pp.push(node(q.sum-b[bb]+b[bb+1],bb+1));//因为a数组第一个元素和b数组第一个
//元素已经保存过了,现在试探b数组第二小元素和a中最小元素组合起来求和
//能否构造新的最小值,这里利用了优先队列的特点自动排序
}
}
}
int main()
{
int n;
while(cin>>n)
{
memset(a,sizeof(a),0);
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>a[i][j];
}
sort(a[i],a[i]+n);
}
for(int i=1;i<n;i++){//因为题目只要求输出前n个最小和
merge(a[0],a[i],a[0],n);
}
cout<<a[0][0];
for(int i=1;i<n;i++){
cout<<" "<<a[0][i];
}
cout<<endl;
}
}