Poj2442 Sequence 贪心+堆优化

本人水平有限,题解不到为处,请多多谅解

本蒟蒻谢谢大家观看

题目传送门

推荐博客

翻译如下:

问题E:Poj2442序列

描述

给定M个长度为N的序列,从每个序列中任取一个数求和,可以构成N ^ M个和,求其中最小的N个和
。N≤2000,M≤100。

输入项

第一行是整数T,它表示测试用例的数量,然后是T个测试用例。 
每种情况的第一行都包含两个整数m,n(0 <m <= 100,0 <n <= 2000)。 
以下m行分别表示m序列。 
序列中没有整数大于10000。

输出量

对于每个测试用例,以递增的顺序打印n个总和最小的行,并用空格隔开。

样本输入

1 
2 3 
1 2 3 
2 2 3

样本输出

3 3 4



注意:每一个数只能用一次

对于2个序列,我们可以先把这两个序列从小到大排序,然后用第一个序列的第一项分别去加第二个序列的各项,得到n个和,放到一个优先队列(大根堆)中;
接下来用第一序列的第二项分别去加第二序列的各项,如果和小于优先队列的首项,那么首项出队,新的和入队,否则结束对第一序列第二项的操作,转而操作第一序列第三项;
如此进行直到操作完第一序列的所有项,得到了第一第二序列各项相加的前n小的和。

那么对于3个序列的问题,我们可以先用上述方法合并前两个序列,得到一个n项的序列,再和第三序列合并出答案。
依次类推即可

要先对每一列进行排序,再根据以上进行操作,当且仅当队列不为空时,把最优解传递下去。

注意:防止PE,注意格式。


code:
 
 1 #include<bits/stdc++.h>
 2 #pragma GCC optimize(3)
 3 using namespace std;
 4 int m,n;
 5 int T;
 6 int f[105][2005];
 7 priority_queue<int> q;
 8 inline int read(){
 9     int x=0,f=1;char ch=getchar();
10     while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
11     while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
12     return x*f;
13 }
14 int main()
15 {    
16     T=read();
17     while(T--)
18     {
19         m=read(),n=read();
20         for(int i=1;i<=m;i++){
21             for(int j=1;j<=n;j++)
22                 f[i][j]=read();
23             sort(f[i]+1,f[i]+1+n);//按照每一列的序列从小到大排序 
24         }
25         for(int i=1;i<m;i++){
26             for(int j=1;j<=n;j++){
27                 q.push(f[i][1]+f[i+1][j]);//第一列的第一个+之后每一列的值 
28             }
29             for(int j=2;j<=n;j++){
30                 for(int k=1;k<=n;k++){//第一列的第二个+之后每一列值 打擂台
31                     if(f[i][j]+f[i+1][k]>=q.top())   break;
32                     else{
33                         q.pop();
34                         q.push(f[i][j]+f[i+1][k]);
35                     }
36                 }
37             }
38             int hhh=n;
39             while(!q.empty()){
40                 f[i+1][hhh]=q.top();//因为是大根堆,所以对顶存储在最后一个 
41                 q.pop();//不断合并两个序列 
42                 hhh--;//依次类推 
43             }
44         }
45         for(int i=1;i<=n;i++){
46             if(i!=1){
47                 printf(" ");//注意格式
48             }
49             printf("%d",f[m][i]);//因为不断合并时最优解是一直传递下来的
50         }
51         printf("
");
52     }
53     return 0;
54 }

“这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。

什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。
人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。

来自博主Bolgggggg



原文地址:https://www.cnblogs.com/nlyzl/p/11724676.html