ZJOI 2008
Z 国的骑士团是一个很有势力的组织,帮会中聚集了来自各地的精英。他们劫富济贫,惩恶扬善,受到了社会各界的赞扬。
可是,最近发生了一件很可怕的事情:邪恶的 Y 国发起了一场针对 Z 国的侵略战争。战火绵延五百里,在和平环境中安逸了数百年的 Z 国又怎能抵挡得住 Y 国的军队。于是人们把所有希望都寄托在了骑士团身上,就像期待有一个真龙天子的降生,带领正义打败邪恶。
骑士团是肯定具备打败邪恶势力的能力的,但是骑士们互相之间往往有一些矛盾。每个骑士有且仅有一个他自己最厌恶的骑士(当然不是他自己),他是绝对不会与最厌恶的人一同出征的。
战火绵延,人们生灵涂炭,组织起一个骑士军团加入战斗刻不容缓!国王交给你了一个艰巨的任务:从所有骑士中选出一个骑士军团,使得军内没有矛盾的两人,即不存在一个骑士与他最痛恨的人一同被选入骑士团的情况,并且使这支骑士军团最富有战斗力。
为描述战斗力,我们将骑士按照 1 至 N 编号,给每位骑士估计一个战斗力,一个军团的战斗力为所有骑士的战斗力之和。
输入格式
输入第一行包含一个正整数 N,描述骑士团的人数;
接下来 N 行每行两个正整数,按顺序描述每一名骑士的战斗力和他最痛恨的骑士。
输出格式
输出包含一行,一个整数,表示你所选出的骑士军团的战斗力。
样例
样例输入
3
10 2
20 3
30 1
样例输出
30
数据范围与提示
对于 30% 的数据,满足 N≤10;
对于 60% 的数据,满足 N≤100;
对于 80% 的数据,满足N≤10^4;
对于 100% 的数据,满足 N≤10^6,且每名骑士的战斗力都是不大于 10^6 的正整数。
_____________________________________________________________________________________________
树形动归,n个点,n条边,那么整个图构成多个联通块,每个块内要么是一棵树,要么是一棵树加一条边构成一个环。
如果是树,直接动归就可以了。
f[u][0]:表示不选当前点的最大战力
f[u][1]:表示选当前点的最大战力
f[u][0]=sum( max( f[v][0],f[v][1] ) )
f[u][1]=sum( f[v][0] )+zl[u];
如果内部是一个树加边,那么环上断开一条边,边的两个端点u,v,他们不能同时取。所以只要求f[u][0]和f[v][0]的较大值就可以了。
_____________________________________________________________________________________________
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn=1e6+10; 5 int n; 6 long long ans; 7 ll zl[maxn]; 8 int hen[maxn]; 9 struct edge 10 { 11 int u,v,nxt; 12 }e[maxn<<1]; 13 int head[maxn],js; 14 void addage(int u,int v) 15 { 16 e[++js].u=u;e[js].v=v; 17 e[js].nxt=head[u];head[u]=js; 18 } 19 bool vis[maxn]; 20 long long f[maxn][2]; 21 int h1,h2,bz=0,root; 22 void dfs(int u,int fa) 23 { 24 if(vis[u]==0) 25 { 26 vis[u]=1; 27 } 28 else 29 { 30 h1=u;h2=fa;bz=1; 31 return; 32 } 33 for(int i=head[u];i;i=e[i].nxt) 34 { 35 int v=e[i].v; 36 if(v!=fa)dfs(v,u); 37 } 38 } 39 void dp(int u,int fa) 40 { 41 f[u][0]=0; 42 f[u][1]=zl[u]; 43 for(int i=head[u];i;i=e[i].nxt) 44 { 45 int v=e[i].v; 46 if(v!=fa && v!=root) 47 { 48 dp(v,u); 49 f[u][0]+=max(f[v][0],f[v][1]); 50 f[u][1]+=f[v][0]; 51 } 52 } 53 } 54 int main() 55 { 56 scanf("%d",&n); 57 for(int i=1;i<=n;++i) 58 { 59 scanf("%d%d",&zl[i],&hen[i]); 60 if(hen[hen[i]]==i)continue; 61 addage(i,hen[i]); 62 addage(hen[i],i); 63 } 64 for(int i=1;i<=n;++i) 65 if(!vis[i]) 66 { 67 h1=h2=bz=0; 68 dfs(i,0); 69 if(bz==0) 70 { 71 root = i; 72 dp(i,0); 73 ans+=max(f[i][0],f[i][1]); 74 } 75 else 76 { 77 root=h1;dp(h1,h2);long long tp=f[h1][0]; 78 root=h2;dp(h2,h1); 79 ans+=max(tp,f[h2][0]); 80 } 81 } 82 cout<<ans; 83 return 0; 84 }