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("
");
48     }
49     return 0;
50 }
“这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”
原文地址:https://www.cnblogs.com/Blogggggg/p/8377071.html