先考虑m=2的情况
将数组排好序 最小的和肯定是a_1+b_1
假设这一个答案为a_i,b_j下一个答案的可能会加入a_i+1,b_j和a_i,b_j+1
把所有可能的下一个加入一个堆
为了避免一个答案被加入两次 ,可以用vis数组或者直接在加入堆时加入一个变量g表示有无移动过j 如果移动过后面就不能移i只能移j,可以保证不会重复选到
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
int t,n,m;
struct node
{
int a[2005];
}s[105];
int p;
struct mes
{
int j,k;
bool g;
bool operator >(const mes b)const
{
return s[p].a[j]+s[p+1].a[k]<s[p].a[b.j]+s[p+1].a[b.k];
}
bool operator <(const mes b)const
{
return s[p].a[j]+s[p+1].a[k]>s[p].a[b.j]+s[p+1].a[b.k];
}
};
mes make_mes(int x,int y,int z)
{
mes ret;
ret.j=x,ret.k=y,ret.g=z;
return ret;
}
priority_queue<mes>q;
int b[2005];
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&m,&n);
for(int i=1;i<=m;++i)
{
for(int j=1;j<=n;++j)
{
scanf("%d",&s[i].a[j]);
}
sort(s[i].a+1,s[i].a+n+1);
}
for(int i=1;i<m;++i)
{
p=i;
while(!q.empty())q.pop();
q.push(make_mes(1,1,0));
for(int j,k,t=1;t<=n;++t)
{
j=q.top().j;
k=q.top().k;
bool ab=q.top().g;
q.pop();
b[t]=s[i].a[j]+s[i+1].a[k];
if(!ab)q.push(make_mes(j+1,k,ab));
q.push(make_mes(j,k+1,1));
}
for(int j=1;j<=n;++j)
{
s[i+1].a[j]=b[j];
}
}
for(int i=1;i<=n;++i)
{
printf("%d ",s[m].a[i]);
}
printf("\n");
}
return 0;
}