博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【BZOJ】2151 种树
阅读量:6756 次
发布时间:2019-06-26

本文共 1462 字,大约阅读时间需要 4 分钟。

【算法】贪心+堆

【题意】n个数字的序列,要求选择互不相邻的k个数字使和最大。

【题解】

贪心,就是按一定顺序选取即可最优,不会反悔。

考虑第一个数字选择权值最大的,那么它相邻的两个数字就不能选择,那么我们可以把这三个数字视为一个整体。操作为将pre[pre[x]]和x和suc[suc[x]]连接起来。

由于可能依然有选择相邻两个数字的可能性,将中间的权值置为A[pre[x]]+A[suc[x]]-A[x],这个权值记录在中间,但实际上代表相邻三个数字的新权值。

若再次选择这个区间,那么就是把区间更新到周围五个数字了(这里的数字有可能已经是一段区间),如此可以不断扩大。

 

贪心原理:若没有间隔种的限制,每次都取大就是最优的。那么多了这个限制之后,取大依然优但却会影响旁边两个数字的选择。

为了使我们依然能贪心,就设置一个反悔的机会,即设置一个新权值。那么如果非要选择旁边两个就相当于选择中间的权值两次,每次把影响区间扩大2并视之为一个数字。

因为贪心就不会反悔的性质,既然会选择这个决策就一定不会悔改。这个反悔的机会实质上是扩大你选择数字的影响范围,一旦扩大就一定不会反悔,因为一定是最优的。

 

每次出现新权值用堆维护。记得开始先特判无法种k棵的情况,因为后面很难判断。

#include
#include
#include
#include
using namespace std;const int maxn=200010;struct cyc{ int num,ord; bool operator < (const cyc &x)const {
return num
q;int a[maxn],pre[maxn],suc[maxn],n,k;bool f[maxn];void del(int x){ f[x]=1; suc[pre[x]]=suc[x]; pre[suc[x]]=pre[x]; suc[x]=pre[x]=0;}int main(){ scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); q.push((cyc){a[i],i}); pre[i]=i-1;suc[i]=i+1; } pre[1]=n;suc[n]=1; int ans=0; if(k>n/2){printf("Error!");return 0;} for(int i=1;i<=k;i++) { while(f[q.top().ord])q.pop(); qp=q.top();q.pop(); ans+=qp.num; int A=pre[qp.ord],B=suc[qp.ord]; a[qp.ord]=a[A]+a[B]-qp.num; del(pre[qp.ord]);del(suc[qp.ord]); q.push((cyc){a[qp.ord],qp.ord}); } printf("%d",ans); return 0;}
View Code

 

转载于:https://www.cnblogs.com/onioncyc/p/7089493.html

你可能感兴趣的文章
随笔1
查看>>
HTML中Select的使用具体解释
查看>>
Java synchronized
查看>>
mysql大内存高性能优化方案
查看>>
VSTO 学习笔记(十二)自定义公式与Ribbon
查看>>
[再寄小读者之数学篇](2015-06-24 Series)
查看>>
【Linux】linux常用基本命令
查看>>
4-python学习——数据操作
查看>>
Oracle函数
查看>>
Unity3D学习笔记第一课
查看>>
【redis使用全解析】常见运维操作
查看>>
hdu2377Bus Pass(构建更复杂的图+spfa)
查看>>
Vc6.0打开该文件坠毁
查看>>
[LeetCode] Lowest Common Ancestor of a Binary Search Tree 二叉搜索树的最小共同父节点
查看>>
2015第29周三
查看>>
hdu5024(dp)
查看>>
算法-无向图(连通分量,是否有环和二分图)
查看>>
IOS runtime动态运行时一
查看>>
媒体播放器三大底层架构
查看>>
CCBValue
查看>>