题目链接:https://vjudge.net/problem/POJ-2442
题目大意:
有 \(m\) 个序列,每个序列 \(n\) 个数。在每个序列中选一个数,会选出 \(m\) 个数,对应一个和。那么对于所有的数,总共有 \(m^n\) 种选法,要求从小到大输出其中和最小的 \(n\) 种选法对应的和。
知识点: 优先队列
解题思路:
对于 \(2\) 个序列,我们可以先把这两个序列从小到大排序,然后用第一个序列的第一项分别去加第二个序列的各项,得到 \(n\) 个和,放到一个优先队列(大顶堆)中;接下来用第一序列的第二项分别去加第二序列的各项,如果和小于优先队列的首项,那么首项出队,新的和入队,否则结束对第一序列第二项的操作,转而操作第一序列第三项;如此进行直到操作完第一序列的所有项,得到了第一第二序列各项相加的前 \(n\) 小的和。
那么对于 \(3\) 个序列的问题,我们可以先用上述方法合并前两个序列,得到一个 \(n\) 项的序列,再和第三序列合并出答案。至于大于 \(3\) 个序列的问题要怎么做,相信读者自己心里已经有答案了吧。
AC代码:
1 #include <iostream> 2 #include <queue> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 8 int m,n; 9 int inp[105][2005]; 10 priority_queue<int> q; 11 int main(){ 12 int T; 13 scanf("%d",&T); 14 while(T--){ 15 scanf("%d%d",&m,&n); 16 for(int i=1;i<=m;i++){ 17 for(int j=1;j<=n;j++) 18 scanf("%d",&inp[i][j]); 19 sort(inp[i]+1,inp[i]+1+n); 20 } 21 for(int i=1;i<m;i++){ 22 for(int j=1;j<=n;j++) q.push(inp[i][1]+inp[i+1][j]); 23 for(int j=2;j<=n;j++){ 24 for(int k=1;k<=n;k++){ 25 if(inp[i][j]+inp[i+1][k]>=q.top()) break; 26 else{ 27 q.pop(); 28 q.push(inp[i][j]+inp[i+1][k]); 29 } 30 } 31 } 32 int ind=n; 33 while(!q.empty()){ 34 inp[i+1][ind]=q.top(); 35 q.pop(); 36 ind--; 37 } 38 } 39 for(int i=1;i<=n;i++){ 40 if(i!=1) printf(" "); 41 printf("%d",inp[m][i]); 42 } 43 printf("\n"); 44 } 45 return 0; 46 }