Poj2442 Sequence 贪心+堆优化
本人水平有限,题解不到为处,请多多谅解
本蒟蒻谢谢大家观看
题目:传送门
推荐:博客
翻译如下:
问题E:Poj2442序列
描述
给定M个长度为N的序列,从每个序列中任取一个数求和,可以构成N ^ M个和,求其中最小的N个和
。N≤2000,M≤100。
。N≤2000,M≤100。
输入项
第一行是整数T,它表示测试用例的数量,然后是T个测试用例。
每种情况的第一行都包含两个整数m,n(0 <m <= 100,0 <n <= 2000)。
以下m行分别表示m序列。
序列中没有整数大于10000。
每种情况的第一行都包含两个整数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("\n"); 52 } 53 return 0; 54 }
“这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。
什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。
人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。
来自博主:Bolgggggg