题目:
You're given k arrays, each array has k integers. There are kk ways to pick exactly one element in each array and calculate the sum of the integers. Your task is to find the k smallest sums among them.
There will be several test cases. The first line of each case contains an integer k (2<=k<=750). Each of the following k lines contains k positive integers in each array. Each of these integers does not exceed 1,000,000. The input is terminated by end-of-file (EOF). The size of input file does not exceed 5MB.
For each test case, print the k smallest sums, in ascending order.
3 1 8 5 9 2 5 10 7 6 2 1 1 1 2
9 10 12 2 2
------------------------------------------------------------------------------------------------------------------------------------------------------------------
思路:
先思考2个有序表(sort后)AB合成的情况。组织如下
【 表】1: A1+B1 <= A1+B2 <= A1+B3 <=......
【表】2:A2+B1 <= A2+B2 <= A2+B3 <=......
......
【表】n:An+B1 <= An+B2 <= An+B3 <=......
转化为多路归并问题且有总数限制为k,因此将n个【表】合并为一个有序【表】C且表中数据数目为k。优先队列处理:初始化优先队列为n个表的第一元素,每次在队列中取出最小元素加入C并将该最小元素在【表】中的后一个元素入队。共取k个元素。
对于k个有序表的情况:两两合并。
于是有代码如下:
1 #include<cstdio> 2 #include<algorithm> 3 #include<queue> 4 #define FOR(a,b,c) for(int a=(b);a<(c);a++) 5 using namespace std; 6 7 const int maxn = 800 + 10; 8 9 struct Node{ 10 int s,b; 11 bool operator <(const Node& rhs) const{ //相反定义 < 12 return s>rhs.s; 13 } 14 }; 15 16 17 void merge(int* A,int* B,int*C,int n){ //合并AB数组取其前n小的和放入C 18 priority_queue<Node> Q; 19 FOR(i,0,n) Q.push(Node{A[i]+B[0],0}); 20 FOR(i,0,n){ 21 Node u=Q.top();Q.pop(); 22 C[i]=u.s; 23 int b=u.b; 24 if(b+1 < n) Q.push(Node{u.s-B[b]+B[b+1],b+1}); //加入A[a][b+1] 25 } 26 } 27 28 int main(){ 29 int n; 30 int A[maxn],B[maxn]; 31 32 while(scanf("%d",&n)==1){ 33 FOR(j,0,n) scanf("%d",&A[j]); sort(A,A+n); 34 FOR(i,1,n){ 35 FOR(j,0,n) scanf("%d",&B[j]); 36 sort(B,B+n); 37 merge(A,B,A,n); 38 } 39 printf("%d",A[0]); 40 FOR(i,1,n) 41 printf(" %d",A[i]); 42 printf("\n"); 43 } 44 return 0; 45 }