[ZJOI2008]骑士(BZOJ 1040)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[ZJOI2008]骑士(BZOJ 1040)相关的知识,希望对你有一定的参考价值。
原题链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1040
此题改编后成为了今天的模拟题之一,也算是本人写的第二道树形DP。
在考虑DP之前,首先要注意一点特殊情况:题目并没有保证这是一棵树,此题中可能有环。
如果没有环,就是一个比较简单的树形DP,
但是此题的环,一定是在根节点上的,为什么?
假设每个骑士痛恨的人都是他的父亲,痛恨他的人是他的儿子,每个点的出度只能为1,一个点如果不是根节点的话,必然有一条连向父亲的边,而父亲又会有一条连向父亲的边。。。根本无法连向其他点构成环,只有根节点,可以痛恨他的一个儿子,从而构成环。
f[i][0]与f[i][1]表示以i为根节点的子树选或不选i能获得的最大价值。
对于每一个尚未经过的点,不断向上寻找,直到下一步将走回一个已经经过的点,将此点设为根节点。
如果有点x能在DP时走回根节点,那么根节点一定不能选。
对于一个环,任意一条边连接的两个点,一个点选中,另一个便不能选,于是就有两种DP方法,所以要DP一次后,再以他的父节点再DP一次。
两种方案的最大值加入最终答案中。
这样就相当于删掉了一些边,可以作为树跑DP了。
#include<cstdio> #include<algorithm> using namespace std; const int inf=(1<<31); const int maxn=2000005; void read(int &y) { y=0;char x=getchar(); while(x<‘0‘||x>‘9‘) x=getchar(); while(x>=‘0‘&&x<=‘9‘) { y=y*10+x-‘0‘; x=getchar(); } } struct edge { int u,v; }e[maxn]; long long f[maxn][2]; int head[maxn],vis[maxn],fa[maxn],p[maxn]; int n,x,root,cnt; long long ans; void add(int u,int v) { e[++cnt].u=head[u]; e[cnt].v=v; head[u]=cnt; } void dp(int x) { vis[x]=1;f[x][0]=0;f[x][1]=p[x]; for(int i=head[x];i;i=e[i].u) { int t=e[i].v; if(t!=root) { dp(t); f[x][0]+=max(f[t][1],f[t][0]); f[x][1]+=f[t][0]; } else f[t][1]=inf; } } int main() { read(n); for(int i=1;i<=n;i++) { read(p[i]);read(x); add(x,i); fa[i]=x; } for(int i=1;i<=n;i++) { if(vis[i]==1) continue; vis[i]=1;root=i; while(vis[fa[root]]==0) { root=fa[root]; vis[root]=1; } dp(root); long long t=max(f[root][0],f[root][1]); root=fa[root]; dp(root); long long s=max(f[root][0],f[root][1]); ans+=max(s,t); } printf("%lld",ans); return 0; }
以上是关于[ZJOI2008]骑士(BZOJ 1040)的主要内容,如果未能解决你的问题,请参考以下文章