博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
树行DP小结
阅读量:5150 次
发布时间:2019-06-13

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

顾名思义:就是在树上做的DP,依据DFS的性质,在访问过儿子之后返回后将儿子的状态传递给父亲...

先看例题:

 

此题用贪心也能过,不过正解是DP。

对于树上的DP我们可以直接考虑最优解下各点的状态来方便我们设状态.显然信号联通的树上各点只有三中状态,自己有塔,儿子有塔,父亲有塔.

那我们设状态时就可以用f[x][0],f[x][1],f[x][2]表示儿子有塔,自己有塔,父亲有塔...

对于1和2的状态比较好转移:

f[x][1]+=min(f[y][1],min(f[y][0],f[y][2]));

f[x][2]+=min(f[y][1],f[y][0]);

 

那对于0的状态,则可以枚举哪个儿子有塔,用计算好的f[x][2]的值:

f[x][0]=min(f[x][0],f[x][2]-min(f[y][1],f[y][0])+f[y][1]); (好好考虑)

初始化,f[x][1]=1;f[x][0]=INT_MAX;

代码:

 

#include
#define _ 0using namespace std;const int maxn=10010;int n,tot,link[maxn],f[maxn][4],fa[maxn]; //f[i][1]表示自己用。struct bian //f[i][0]表示儿子用.f[i][2]表示父亲用. { int y,next;};bian a[2*maxn];inline void add(int x,int y){ a[++tot].y=y; a[tot].next=link[x]; link[x]=tot;}inline void dfs(int x){ f[x][1]=1;f[x][0]=INT_MAX; for(int i=link[x];i;i=a[i].next) { int y=a[i].y; if(y==fa[x]) continue; fa[y]=x; dfs(y); f[x][1]+=min(f[y][1],min(f[y][0],f[y][2])); f[x][2]+=min(f[y][1],f[y][0]); } for(int i=link[x];i;i=a[i].next) { int y=a[i].y; if(y==fa[x]) continue; f[x][0]=min(f[x][0],f[x][2]-min(f[y][1],f[y][0])+f[y][1]); } } int main(){ //freopen("1.in","r",stdin); cin>>n; for(int i=1;i
>x>>y; add(x,y);add(y,x); } dfs(1); cout<

 

下一题:

 

 

这道题同样是树上跑DP.

状态很好想,f[x][j]表示x的节点保留j条树枝的最大值.

#include
#define _ 0using namespace std;const int maxn=110;int n,Q,tot,link[maxn],f[maxn][maxn],size[maxn],fa[maxn],deep[maxn];struct bian //f[i][j]表示i点保留了j条边的最大苹果数. { int y,v,next;};bian a[2*maxn];inline void add(int x,int y,int v){ a[++tot].y=y; a[tot].v=v; a[tot].next=link[x]; link[x]=tot;}inline void dfs(int x){ size[x]=1; for(int i=link[x];i;i=a[i].next) { int y=a[i].y; if(deep[y]) continue; deep[y]=deep[x]+1; //计算它的深度. dfs(y); size[x]+=size[y]; //计算以其为根节点的子树数量 for(int j=min(Q-deep[x]+1,size[x]-1);j>=0;--j) //见下 for(int k=min(Q-deep[y]+1,min(size[y]-1,j-1));k>=0;--k) //见下 f[x][j]=max(f[x][j],f[x][j-k-1]+f[y][k]+a[i].v); }}int main(){ freopen("1.in","r",stdin); cin>>n>>Q; for(int i=1;i<=n;i++) { int x,y,v; cin>>x>>y>>v; add(x,y,v);add(y,x,v); } deep[1]=1; //对深度初始化. dfs(1); cout<
<

这里主要讲j和k的范围,想说j,Q-deep[x]+1表示要想选到x这个点必须保留deep[x]+1个树枝.size[x]-1表示x此时最多选的树枝.

同理,k还多了个j-1,因为还要选x到y这条边,所以要建议.

这里警告我:状态转移必须在合理的范围内,否则会出现不可预计的后果.还有f循环的顺序考虑清楚.

例如此题j就必须是倒序的。因为是拿y来更新x的,比如假如正序:拿f[y][1]更新过f[x][2]后,又拿f[X][2]更新f[x][3]这就不符合情况.此时倒序,由大的枚举就不会出现这种情况了。

好了,就到这了.

转载于:https://www.cnblogs.com/gcfer/p/11137795.html

你可能感兴趣的文章
浏览器对属性兼容性支持力度查询网址
查看>>
OO学习总结与体会
查看>>
虚拟机长时间不关造成的问题
查看>>
toString和valueOf的区别
查看>>
C#操作Excel(创建、打开、读写、保存)几种方法的总结
查看>>
校门外的树2 contest 树状数组练习 T4
查看>>
JS及JQ使用JSONP实现跨域调用必应搜索
查看>>
面试整理:Python基础
查看>>
Python核心编程——多线程threading和队列
查看>>
关于Invoke和InvokeRequired
查看>>
Program exited with code **** 相关解释
查看>>
装服务器,测试数据库,简单的maven命令
查看>>
升级Firefox8后watir-webdriver出现错误“unable to obtain stable firefox connection in 60 seconds”...
查看>>
第6章 Overlapped I/O, 在你身后变戏法 ---被激发的 Event 对象 -4
查看>>
植物大战僵尸中文年度版
查看>>
26、linux 几个C函数,nanosleep,lstat,unlink
查看>>
001.RAID简介
查看>>
投标项目的脚本练习2
查看>>
第五次实验
查看>>
201521123107 《Java程序设计》第9周学习总结
查看>>