UVA 11997 STL 优先队列
题目链接:
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3148
题意:给K个数组,每个数组含有K个整数,从每个数组中各选一个数加起来,得到一个sum,这样的选法一共有K^k种,现在求这样的和中最小的K个sum.
解法:先考虑两个数组的情形
假设A1<=A2<=`````<=AK
B1<=B2<=`````<=Bk
则有
A1+B1<=A1+B2<=`````<=A1+Bk.
A2+B1<=A2+B2<=`````<=A2+Bk.
```````
Ak+B1<=Ak+B2<=`````<=Ak+Bk.
首先把第一列的数<s[i] = A[i] + B[1] , 1>,第一个数为和,第二个数为B的序号,放入优先队列,然后从优先队列中弹出最小的,这个最小值一定是所有和中最小的,同时压入A[a] + B[b+1],A[a]+B[b+1] = s-B[b]+B[b+1]....这样循环n次即可。得到了n个最小和。因为这里有k个数组,两两合并即可。
以上摘自刘汝佳的大白书190页。(是看了他的书写的,如果有错了不是他写错了,必然是我写错了)
贴代码:
1 #include<cstdio> 2 #include<algorithm> 3 #include<queue> 4 using namespace std; 5 #define N 755 6 int k[N][N],n; 7 struct Item 8 { 9 int s,b;//s = A[a] + B[b] 10 Item(int s,int b):s(s),b(b) {} 11 bool operator<(const Item & other)const 12 { 13 return s > other.s; 14 } 15 }; 16 void output(int a[]) 17 { 18 printf("array :\n"); 19 for(int i=0; i<n; ++i) 20 printf("%d ",a[i]); 21 puts(""); 22 } 23 void combine(int A[],int B[]) 24 { 25 priority_queue<Item> q; 26 for(int i =0; i<n; ++i) 27 q.push(Item(A[i]+B[0] , 0)); 28 for(int i=0; i<n; ++i) 29 { 30 Item item = q.top(); 31 q.pop(); 32 A[i] = item.s; 33 int b = item.b; 34 if(b+1 < n ) q.push(Item(item.s - B[b] + B[b+1] , b+1)); 35 } 36 } 37 int main() 38 { 39 // freopen("in.txt","r",stdin); 40 while(~scanf("%d",&n)) 41 { 42 for(int i=0; i<n; ++i) 43 { 44 for(int j=0; j<n; ++j) 45 scanf("%d",&k[i][j]); 46 sort(k[i],k[i]+n); 47 } 48 for(int i=1; i<n; ++i) 49 combine(k[0],k[i]); 50 printf("%d",k[0][0]); 51 for(int i=1; i < n; ++i) 52 printf(" %d",k[0][i]); 53 puts(""); 54 } 55 return 0; 56 }