口胡一个结论:就是前i行产生的最小的n个和,一定可以在"前i-1行产生的最小n个和,每一个加上这一行的任意一个数,产生的n2个数"中找到。(其实显然是对的)
因此每次只需要求两个有n个数的序列每个序列中选一个产生的所有和中最小n个。方法就是先将两个序列排序,这之后去模拟一个一个取出和的过程。如果第一个序列取的已经确定,那么第二个序列一定是按顺序取。因此枚举第一个序列中取某一个,对于第一个序列中取某一个的情况维护当前已经取到的第二个序列中的序号。用优先队列维护最小的和,每次取出一个放进当前答案的数组,并将该和对应的第一个序列取法对应的第二个序列的序号加一并放回优先队列。
错误原因:
1.44行写成t[i],会被只有一行的数据卡掉
2.求两行合并的时候用了n2算法,太暴力
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<queue> 5 using namespace std; 6 typedef int LL; 7 typedef pair<LL,LL> P; 8 typedef pair<LL,P> P2; 9 priority_queue<P2,vector<P2>,greater<P2> > qq; 10 LL a[105][2005]; 11 LL t[2005]; 12 LL T,sum,m,n; 13 int main() 14 { 15 P2 x; 16 LL i,j; 17 scanf("%d",&T); 18 while(T--) 19 { 20 memset(a,0,sizeof(a)); 21 memset(t,0,sizeof(t)); 22 scanf("%d%d",&m,&n); 23 for(i=1;i<=m;i++) 24 { 25 for(j=1;j<=n;j++) 26 scanf("%d",&a[i][j]); 27 sort(a[i]+1,a[i]+n+1); 28 } 29 for(i=2;i<=m;i++) 30 { 31 while(!qq.empty()) qq.pop(); 32 for(j=1;j<=n;j++) 33 qq.push(P2(a[i-1][j]+a[i][1],P(j,1))); 34 for(j=1;j<=n;j++) 35 { 36 x=qq.top(); 37 qq.pop(); 38 t[j]=x.first; 39 qq.push(P2(a[i-1][x.second.first]+a[i][x.second.second+1],P(x.second.first,x.second.second+1))); 40 } 41 memcpy(a[i],t,sizeof(t)); 42 } 43 for(i=1;i<=n;i++) 44 printf("%d ",a[m][i]); 45 puts(""); 46 } 47 return 0; 48 }