题目大意

有k个整数数组,各包含k个元素。在每个数组中取一个元素加起来。可以得到kk个和。求这些和中最小的k个值(重复的值算多次)
输入格式
输入包含多组数据。每组数据第一行为一个整数k(2≤k≤750)。以下k行每行包含k个不超过106。输入结束标志位文件结束符(EOF)。输入文件不超过5MB.
输出格式
对于每组数据,输出k个最小和的值,并按照从小到大的顺序排序。

题目分析

若只有两列数 则有 n 2 n^2 n2种情况
那么,我们要取前k种
可以根据 将其构成 n张 有序表
a,b都有序的情况下
a [ 1 ] + b [ 1 ] a [ 1 ] + b [ 2 ] . . . a [ 1 ] + b [ n ] a[1]+b[1] \le a[1]+b[2] \le ... \le a[1]+b[n] a[1]+b[1]a[1]+b[2]...a[1]+b[n]
a [ 2 ] + b [ 1 ] a [ 2 ] + b [ 2 ] . . . a [ 2 ] + b [ n ] a[2]+b[1] \le a[2]+b[2] \le ... \le a[2]+b[n] a[2]+b[1]a[2]+b[2]...a[2]+b[n]
a [ n ] + b [ 1 ] a [ n ] + b [ 2 ] . . . a [ n ] + b [ n ] a[n]+b[1] \le a[n]+b[2] \le ... \le a[n]+b[n] a[n]+b[1]a[n]+b[2]...a[n]+b[n]

而 已知 a[1]+b[1] =s
s’ = a[1]+[b2] = s-b[1]+b[2]
因此,我们直接将 a[i]+b[1] ( 1 i n 1 \le i \le n 1in)放入优先队列中 ,然后递推得出 后面的项。不断放入优先队列里。取出前k项即可。

但是这样我们有可能会将第二个数组的中数值加多次,但是,我们可以证明
a [ i ] + b [ x ] + b [ y ] a [ i ] + b [ x ] , a [ i ] + b [ x ] + b [ y ] a [ i ] + b [ y ] a[i]+b[x]+b[y] \le a[i]+b[x] , a[i]+b[x]+b[y] \le a[i]+b[y] a[i]+b[x]+b[y]a[i]+b[x],a[i]+b[x]+b[y]a[i]+b[y]
这两个式子恒成立。
所以 当 k n k \le n kn时,一定不会取到 a[i]+b[x]+b[y]
然而目前,有 n列数
那么只要每次合并两个,合并n次即可

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000;
int a[maxn][maxn];
int ans[maxn];
int n;
struct node
{
	int s,k;
	bool operator<(const node&oth)const
	{
		return oth.s<s;
	}
	node(int _s,int _k):s(_s),k(_k){}
};
void getans(int t)
{
	//cout<<"round = "<<t<<endl;
	priority_queue<node>pq;
	for(int i=1;i<=n;i++)
	{
		pq.push(node(a[t][1]+ans[i],1));
	}
	for(int i=1;i<=n;i++)
	{
		node tmp = pq.top();
		pq.pop();
		ans[i]=tmp.s;
		//cout<<tmp.s<<" "<<tmp.k<<endl;
		tmp.s  = tmp.s-a[t][tmp.k]+a[t][tmp.k+1];
		//cout<<"s= "<<tmp.s<<endl;
		if(tmp.k+1<=n) {
			//cout<<"push in"<<tmp.s<<" "<<tmp.k+1<<endl;
			pq.push(node(tmp.s,tmp.k+1));
		}
		//cout<<ans[i]<<" "<<endl;
	}
	//cout<<endl;
}
int main()
{
	while(scanf("%d",&n)!=EOF)
	{
		memset(a,0,sizeof(a));
		memset(ans,0,sizeof(ans));
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				scanf("%d",&a[i][j]);
			}
			sort(a[i]+1,a[i]+1+n);
		}
		for(int i=1;i<=n;i++) ans[i]=a[1][i];
		for(int i=2;i<=n;i++)
			getans(i);

		for(int i=1;i<=n;i++)
		{
			if(i==n) printf("%d\n",ans[i]);
			else printf("%d ",ans[i]);
		}
	}
	return 0;
}