UVA11997 K Smallest Sums

本篇是刘汝佳《算法竞赛入门经典——训练指南》的读书笔记。

知识点:  优先队列

解题思路:

  先考虑\(2\)个包含\(k\)个元素的数组的情况:在每个数组中取一个数加起来,可以得到\(2^k\)个和,求这些和中最小的\(k\)个值。做法是先将两个数组从小到大排好序,然后先取数组\(A\)的最小值与数组\(B\)的各个值相加,放进一个从小到大排列的优先队列中,接下来每次取出优先队列的队首元素(即目前的最小值),在此基础上更新这个值(即把这个值中数组\(B\)的值稍微增大一点),让新值入队,取出\(k\)个最小的即可结束。

  那么对于\(k\)个包含\(k\)个元素的数组又该怎么做呢?易知上述的操作能把两个数组合并成一个,则只需进行\(k-1\)次操作,将\(k\)个数组两两合并为一组即可。

AC代码:

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 const int maxn = 770;
 5 
 6 int inp[maxn][maxn];
 7 int ans[maxn];
 8 struct Item{
 9     int sum,b;
10     bool operator <(const Item &rhs)const{
11         return sum>rhs.sum;
12     }
13 };
14 int main()
15 {
16     priority_queue<Item> q;
17     int k;
18     while(scanf("%d",&k)==1){
19         for(int i=0;i<k;i++){
20             for(int j=0;j<k;j++)    scanf("%d",&inp[i][j]);
21             sort(inp[i],inp[i]+k);
22         }
23         for(int j=0;j<k;j++)    ans[j]=inp[0][j];
24 
25         Item now;
26         for(int i=1;i<k;i++){
27             while(!q.empty())   q.pop();
28             now.b=0;
29             for(int j=0;j<k;j++){
30                 now.sum=ans[j]+inp[i][0];
31                 q.push(now);
32             }
33             int ind=0;
34             while(ind<k){
35                 now=q.top();
36                 q.pop();
37                 ans[ind++]=now.sum;
38                 if(now.b+1<k){
39                     now.sum=now.sum-inp[i][now.b]+inp[i][now.b+1];
40                     now.b++;
41                     q.push(now);
42                 }
43             }
44         }
45         printf("%d",ans[0]);
46         for(int i=1;i<k;i++)    printf(" %d",ans[i]);
47         printf("\n");
48     }
49     return 0;
50 }

 

posted @ 2018-01-29 14:16  Blogggggg  阅读(144)  评论(0编辑  收藏  举报