刘汝佳新书---训练指南
题意:有K个整数数组,包含K个元素。在每个数组中取一个元素加起来,可以得到k^k个和。求这些和中最小的K个值
分析:这题有简化版本的,即2个整数数组A,B,包含K个元素,在每个数组中取一个元素加起来,可以得到k^2个和,求这些和中最小的K个值。
我们需要把这k^2个和组织成如下k个有序表.
表1:A1+B1<=A1+B2<=......<=A1+Bk
表2: A2+B1<=A2+B2<=......<=A2+Bk
表k:Ak+B1<=AK+B2<=......<=Ak+Bk
我们可以用二元组(s,b)来表示一个元素即s=Aa+Bb;为什么不保存A的下标a呢?因为我们用不到a的值。如果我们需要元素(s,b)在表a的下一个元素(s',b+1).只需要计算s'=s+B[b+1]-B[b];
这样我们先将K个表的第一个元素压入优先队列,这样队列中就用k个元素了。然后从队列中出一个值,就压入这个值所在表的下一个元素,直到k个值都出了优先队列。这样就得到k个最小值了。。
然后对与K个数组。我们只需两两合并即可。
// File Name: 11997.cpp // Author: zlbing // Created Time: 2013/3/8 20:19:01 #include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> #include<cmath> #include<queue> using namespace std; #define CL(x,v); memset(x,v,sizeof(x)); #define INF 0x3f3f3f3f #define LL long long #define REP(i,n) for(int i=0;i<n;i++) #define REP1(i,n) for(int i=1;i<n+1;i++) #define MAXN 1000 int G[MAXN][MAXN]; int k; struct Item{ int s,b; bool operator <(const Item& r)const{ return s>r.s; } }; void merge(int *A,int *B,int *C){ int cnt=0; priority_queue<Item> Q; for(int i=0;i<k;i++)Q.push((Item){A[i]+B[0],0}); while(!Q.empty()){ Item t=Q.top(); Q.pop(); C[cnt++]=t.s; if(t.b+1<k)Q.push((Item){t.s+(B[t.b+1]-B[t.b]),t.b+1}); if(cnt==k)break; } //for(int i=0;i<k;i++)printf("%d ",C[i]); } int main(){ while(~scanf("%d",&k)) { REP(i,k){ REP(j,k) scanf("%d",&G[i][j]); sort(G[i],G[i]+k); } REP1(i,k-1)merge(G[0],G[i],G[0]); REP(i,k) if(i==0)printf("%d",G[0][i]); else printf(" %d",G[0][i]); printf("\n"); } return 0; }