https://vjudge.net/problem/UVA-11997
题意:
给出k个数组,每个数组中有k个元素,要求从每个数组中选择一个元素相加得到的K^K个数中选择最小的k个并输出。
思路:
如果直接模拟,那么就是k^k的复杂度,显然是不能接受的。。。
首先看有两个数组的情况,先把A,B两个数组排序,把每一个A数组中的元素加B[0] 和 B[0]的下标 保存在一个结构体当中,扔进一个优先队列,
这个优先队列的优先级是sum小为队首(求的是最小值)。
之后从0到k - 1枚举,每次从优先队列中取一个元素,那么当前的sum肯定是最小的,于是记录,之后看看这个结构体保存的下标,如果小于K - 1的话,
那么就把sum - B[id].sum + B[id+1].sum和id+1丢进优先队列。这一步实际就保证了优先队列的队首始终是最小的元素并且元素不会重复加。
因为第一个比B[id].sum大的元素就是B[id+1].sum,所以sum - B[sum]实际是当前的A[i].sum,因为B[id].sum已经用过了,所以B[id+1].sum + A[i].sum进队就保证了当前队列中的k个元素一定是最小的。
那么K个数组,其实每次读入一个合并一次就好了。
这叫多路归并问题(不懂
具体还是结合代码理解,能手算理解一下更好!
代码:
1 #include <stdio.h> 2 #include <queue> 3 #include <algorithm> 4 using namespace std; 5 6 struct node 7 { 8 long long sum; 9 int b; 10 11 bool operator < (const node& rhs) const 12 { 13 return rhs.sum < sum; 14 } 15 }; 16 17 node a[755],c[755]; 18 19 int k; 20 21 void unit(void) 22 { 23 priority_queue<node> pq; 24 25 while (!pq.empty()) pq.pop(); 26 27 for (int i = 0;i < k;i++) 28 { 29 pq.push(node{a[i].sum + c[0].sum,0}); 30 } 31 32 for (int i = 0;i < k;i++) 33 { 34 a[i].sum = pq.top().sum; 35 int id = pq.top().b; 36 37 pq.pop(); 38 39 if (id < k - 1) 40 { 41 pq.push(node{a[i].sum - c[id].sum + c[id+1].sum,id + 1}); 42 } 43 44 } 45 } 46 47 bool cmp(node aa,node bb) 48 { 49 return aa.sum < bb.sum; 50 } 51 52 int main() 53 { 54 55 56 while (scanf("%d",&k) != EOF) 57 { 58 for (int i = 0;i < k;i++) 59 { 60 scanf("%lld",&a[i].sum); 61 } 62 63 for (int i = 1;i < k;i++) 64 { 65 for (int j = 0;j < k;j++) 66 { 67 scanf("%lld",&c[j].sum); 68 } 69 70 sort(a,a+k,cmp); 71 sort(c,c+k,cmp); 72 73 for (int j = 0;j < k;j++) c[j].b = j; 74 75 unit(); 76 } 77 78 sort(a,a+k); 79 80 for (int i = k - 1;i >= 0;i--) 81 { 82 printf("%d%c",a[i].sum,i == 0 ? ' ' : ' '); 83 } 84 } 85 86 return 0; 87 }