【环套树+树形dp】Bzoj1040 [ZJOI2008] 骑士

Description

Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英。他们劫富济贫,惩恶扬善,受到社会各界的赞扬。最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争。战火绵延五百里,在和平环境中安逸了数百年的Z国又怎能抵挡的住Y国的军队。于是人们把所有的希望都寄托在了骑士团的身上,就像期待有一个真龙天子的降生,带领正义打败邪恶。骑士团是肯定具有打败邪恶势力的能力的,但是骑士们互相之间往往有一些矛盾。每个骑士都有且仅有一个自己最厌恶的骑士(当然不是他自己),他是绝对不会与自己最厌恶的人一同出征的。战火绵延,人民生灵涂炭,组织起一个骑士军团加入战斗刻不容缓!国王交给了你一个艰巨的任务,从所有的骑士中选出一个骑士军团,使得军团内没有矛盾的两人(不存在一个骑士与他最痛恨的人一同被选入骑士军团的情况),并且,使得这支骑士军团最具有战斗力。为了描述战斗力,我们将骑士按照1至N编号,给每名骑士一个战斗力的估计,一个军团的战斗力为所有骑士的战斗力总和。

 

Solution

如果不会形成环那么就是经典的最大独立集问题。

但因为n个点n条边,所以只会有一个环,于是很好讨论。

每次找出一个连通块以及让这个连通块形成环的边(u,v),dp两次,分别强制不选u和v,这样就排出了这条边的影响,普通dp就行了。

思路很清楚,不过感觉我做的树形dp还是太少了,不够熟QwQ

 

Code

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #define ll long long
 5 using namespace std;
 6 const int maxn=1e6+5;
 7 
 8 int c[maxn],n;
 9 int head[maxn],e[maxn*2],nxt[maxn*2],k;
10 int adde(int u,int v){
11     e[++k]=v;nxt[k]=head[u];head[u]=k;
12     e[++k]=u;nxt[k]=head[v];head[v]=k;
13 }
14 
15 int dfn[maxn];
16 int r1,r2,xx;
17 int cir(int p,int u){
18     dfn[u]=1;
19     for(int i=head[u];i;i=nxt[i]){
20         int v=e[i];
21         if(v==p) continue;
22         if(dfn[v]){
23             r1=u,r2=v;
24             xx=i;
25         }
26         else cir(u,v);
27     }
28 }
29 
30 int dy(int x){
31     if(x%2==1) return x+1;
32     else  return x-1;
33 }
34 
35 ll f[maxn][2];
36 int vis[maxn];
37 int dp(int u){
38     vis[u]=1;
39     f[u][1]=c[u];
40     for(int i=head[u];i;i=nxt[i]){
41         if(i==xx||dy(i)==xx) continue;
42         int v=e[i];
43         if(!vis[v]){
44             dp(v);
45             f[u][0]+=max(f[v][1],f[v][0]);
46             f[u][1]+=f[v][0];
47         }
48     }
49 }
50 
51 int main(){
52     scanf("%d",&n);
53     int to;
54     for(int i=1;i<=n;i++){
55         scanf("%d%d",&c[i],&to);
56         adde(i,to);
57     }
58     
59     ll ansx=0,ans=0;
60     for(int i=1;i<=n;i++)
61         if(!dfn[i]){
62             cir(0,i);
63             memset(vis,0,sizeof(vis));
64             memset(f,0,sizeof(f));
65             dp(r1); ansx=f[r1][0];
66             
67             memset(vis,0,sizeof(vis));
68             memset(f,0,sizeof(f));
69             dp(r2); ansx=max(ansx,f[r2][0]);
70             ans+=ansx;
71         }
72         
73     printf("%lld\n",ans);
74     return 0;
75 }
View Code

 

posted @ 2015-06-06 10:41  CyanNode  阅读(246)  评论(0编辑  收藏  举报