先看简化版:给出2个长度为n的有序表A和B,分别在A和B中任取一个数相加,可以得到n^2个和,求这些和中最小的n个和。
解决了简化版,那么一样的一组一组合并就好了。
转化为多路归并问题。
我们先把这n^2个数组织成如下n个有序列。
列1:A1+B1<=A1+B2<=A1+B3...列2:A2+B1<=A2+B2<=A2+B3...
列n:An+B1<=An+B2<=An+B3...
用一个struct(s,b)表示一个元素
其中s=Aa+Bb,这样我们要得到(s,b)的下一个(s',b+1), 只要使s'=s-Bb+B(b+1)即可。
1 #include <iostream> 2 #include <algorithm> 3 #include <map> 4 #include <vector> 5 #include <functional> 6 #include <string> 7 #include <cstring> 8 #include <queue> 9 #include <set> 10 #include <cmath> 11 #include <cstdio> 12 13 14 using namespace std; 15 #define IOS ios_base::sync_with_stdio(false) 16 typedef long long LL; 17 const int INF = 0x3f3f3f3f; 18 const double PI=4.0*atan(1.0); 19 20 const int maxn=800; 21 typedef struct Item{ 22 int s,b; 23 Item(int s,int b):s(s),b(b){} 24 bool operator<(const Item &a) const{ 25 return s>a.s; 26 } 27 }I; 28 int k,a[maxn],b[maxn]; 29 void merge(int *a,int *b,int *c) 30 { 31 sort(a,a+k); 32 sort(b,b+k); 33 priority_queue<I> que; 34 for(int i=0;i<k;i++) 35 que.push(I(a[i]+b[0],0)); 36 for(int i=0;i<k;i++){ 37 I it=que.top(); que.pop(); 38 c[i]=it.s; 39 if(it.b<k-1) que.push(I(it.s-b[it.b]+b[it.b+1],it.b+1)); 40 } 41 } 42 int main() 43 { 44 while(scanf("%d",&k)!=EOF){ 45 for(int i=0;i<k;i++) scanf("%d",&a[i]); 46 for(int i=0;i<k-1;i++){ 47 for(int j=0;j<k;j++) scanf("%d",&b[j]); 48 merge(a,b,a); 49 } 50 for(int i=0;i<k-1;i++) printf("%d ",a[i]); 51 printf("%d ",a[k-1]); 52 } 53 }