题目:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18702
题意:N行N列矩阵,每行选一个数求和,选出前N个最小的和。
代码:
/*
简化问题:
a和b两个序列都有n个元素,从a何b中各选一个元素求和,有n*n种情况,找出
前n小的n个和。
考虑所有情况:
a[1]+b[1] a[1]+b[2] a[1]+b[3] a[1]+b[4] 。。。
a[2]+b[1] a[2]+b[2] a[2]+b[3] a[2]+b[4]。。。
a[3]+b[1] a[3]+b[2] a[3]+b[3] a[3]+b[4]。。。
a[4]+b[1] a[4]+b[2] a[4]+b[3] a[4]+b[4]。。。
。。。。。
分析:
若将b[]从小到大排序,那么最小的和就应该在第一列。
然后将最小的那个值选出,值后面的n-1个值向前移位,
那么,最小的和还应该在第一列。
解决:
用优先队列维护第一列的值就行了。
扩展:n路合并
*/
#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
struct node
{
int s,p;
node(int a=0,int b=0)
:s(a),p(b){}
bool operator < (const node &t)const
{
return s>t.s;
}
};
priority_queue <node > q;
int N,f[1000],t[1000];
void Merge(int a[],int b[])
{
while(!q.empty())
q.pop();
for(int i=0;i<N;i++)
q.push(node(a[i]+b[0],0));
node temp;
for(int i=0;i<N;i++)
{
temp=q.top();
q.pop();
a[i]=temp.s;
if(temp.p+1<N)
q.push(node(temp.s-b[temp.p]+b[temp.p+1],temp.p+1));
}
}
int main()
{
int i,j;
while(scanf("%d",&N)!=EOF)
{
for(i=0;i<N;i++)
scanf("%d",&f[i]);
for(i=1;i<N;i++)
{
for(j=0;j<N;j++)
scanf("%d",&t[j]);
sort(t,t+N);
Merge(f,t);
}
printf("%d",f[0]);
for(i=1;i<N;i++)
printf(" %d",f[i]);
printf("\n");
}
return 0;
}