BZOJ 1040 [ZJOI2008]骑士 (基环树+树形DP)
<题目链接>
题目大意:
Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英。他们劫富济贫,惩恶扬善,受到社会各界的赞扬。最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争。战火绵延五百里,在和平环境中安逸了数百年的Z国又怎能抵挡的住Y国的军队。于是人们把所有的希望都寄托在了骑士团的身上,就像期待有一个真龙天子的降生,带领正义打败邪恶。骑士团是肯定具有打败邪恶势力的能力的,但是骑士们互相之间往往有一些矛盾。每个骑士都有且仅有一个自己最厌恶的骑士(当然不是他自己),他是绝对不会与自己最厌恶的人一同出征的。战火绵延,人民生灵涂炭,组织起一个骑士军团加入战斗刻不容缓!国王交给了你一个艰巨的任务,从所有的骑士中选出一个骑士军团,使得军团内没有矛盾的两人(不存在一个骑士与他最痛恨的人一同被选入骑士军团的情况),并且,使得这支骑士军团最具有战斗力。为了描述战斗力,我们将骑士按照1至N编号,给每名骑士一个战斗力的估计,一个军团的战斗力为所有骑士的战斗力总和。
解题分析:
比较经典的基环树(环套树)。本题给出一个$n$条边$n$个点的有向图,我们可以发现,因为本题有向边表示这两个人至多只能出现其中一个,是用来表示一种关系的,所以在实际意义上,完全可以用无向边来代替。于是,本题就转化成了基环树森林,基环树的主要突破口就是要找出每个基环树的环(每个连通分量都是一颗基环树),然后将环中的一条边拆掉,使其变成一棵树,分别以拆掉的边的两个端点作为树的根,然后进行树形DP。本题就变成了对于树上有关系的两个点,只能选一个,使得最后的总价值最大,这就变成了一个比较经典的树形DP模型(比如上司的舞会)。
注意拆环的时候,强制一个点为根,并且不选,因为尽管我们拆除了那条边,但它还是正实存在的,所以只有不选的状态才能避免这两个点都被选中(防止违反题意)。
#include <bits/stdc++.h> using namespace std; #define clr(a,b) memset(a,b,sizeof(a)) #define REP(i,s,t) for(int i=s;i<=t;i++) const int N = 1e6+5; typedef long long ll; struct Edge{ int to,nxt; }e[N<<1]; int n,m,cnt,head[N]; int Ecut,rt,urt; int w[N],vis[N]; ll dp[N][2]; inline void init(){ cnt=0;clr(head,-1);clr(vis,0);clr(dp,0); } inline void add(int u,int v){ e[cnt]=(Edge){ v,head[u] };head[u]=cnt++; } void dfs(int u,int pre){ vis[u]=1; for(int i=head[u];~i;i=e[i].nxt){ int v=e[i].to; if(v==pre)continue; if(!vis[v])dfs(v,u); else { //如果找到环了 rt=u,urt=v,Ecut=i; //记录下这个环的两个端点,并且记录这个拆除的边 } } } void trdp(int u,int pre){ dp[u][1]=w[u]; //表示选当前这个点的价值 dp[u][0]=0; //表示不选当前这个点的价值 for(int i=head[u];~i;i=e[i].nxt){ int v=e[i].to; if(i==Ecut || i==(Ecut^1) || v==pre)continue; trdp(v,u); dp[u][1]+=dp[v][0]; dp[u][0]+=max(dp[v][0],dp[v][1]); } } int main(){ while(~scanf("%d",&n)){ init(); REP(i,1,n){ int now;scanf("%d%d",&w[i],&now); add(i,now);add(now,i); } ll sum=0; REP(i,1,n) if(!vis[i]) { dfs(i,-1); //基环树森林,每个连通分量中必有一个环 trdp(rt,-1); //以拆分的两个点分别为根,进行树形DP ll tmp = dp[rt][0]; trdp(urt,-1); sum+=max(tmp,dp[urt][0]); } printf("%lld\n",sum); } }
作者:is_ok
出处:http://www.cnblogs.com/00isok/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。