版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hwzzyr/article/details/78241569
【ZJOI2008】骑士
Description
Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英。他们劫富济贫,惩恶扬善,受到社会各界的赞扬。
最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争。战火绵延五百里,在和平环境中安逸了数百年的Z国又怎能抵挡的住Y国的军队。于是人们把所有的希望都寄托在了骑士团的身上,就像期待有一个真龙天子的降生,带领正义打败邪恶。
骑士团是肯定具有打败邪恶势力的能力的,但是骑士们互相之间往往有一些矛盾。每个骑士都有且仅有一个自己最厌恶的骑士(当然不是他自己),他是绝对不会与自己最厌恶的人一同出征的。
战火绵延,人民生灵涂炭,组织起一个骑士军团加入战斗刻不容缓!国王交给了你一个艰巨的任务,从所有的骑士中选出一个骑士军团,使得军团内没有矛盾的两人(不存在一个骑士与他最痛恨的人一同被选入骑士军团的情况),并且,使得这支骑士军团最具有战斗力。
为了描述战斗力,我们将骑士按照1至N编号,给每名骑士一个战斗力的估计,一个军团的战斗力为所有骑士的战斗力总和。
最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争。战火绵延五百里,在和平环境中安逸了数百年的Z国又怎能抵挡的住Y国的军队。于是人们把所有的希望都寄托在了骑士团的身上,就像期待有一个真龙天子的降生,带领正义打败邪恶。
骑士团是肯定具有打败邪恶势力的能力的,但是骑士们互相之间往往有一些矛盾。每个骑士都有且仅有一个自己最厌恶的骑士(当然不是他自己),他是绝对不会与自己最厌恶的人一同出征的。
战火绵延,人民生灵涂炭,组织起一个骑士军团加入战斗刻不容缓!国王交给了你一个艰巨的任务,从所有的骑士中选出一个骑士军团,使得军团内没有矛盾的两人(不存在一个骑士与他最痛恨的人一同被选入骑士军团的情况),并且,使得这支骑士军团最具有战斗力。
为了描述战斗力,我们将骑士按照1至N编号,给每名骑士一个战斗力的估计,一个军团的战斗力为所有骑士的战斗力总和。
Input
输入文件knight.in第一行包含一个正整数N,描述骑士团的人数。
接下来N行,每行两个正整数,按顺序描述每一名骑士的战斗力和他最痛恨的骑士。
接下来N行,每行两个正整数,按顺序描述每一名骑士的战斗力和他最痛恨的骑士。
Output
输出文件knight.out应包含一行,包含一个整数,表示你所选出的骑士军团的战斗力。
Sample Input
3
10 2
20 3
30 1
10 2
20 3
30 1
Sample Output
30
Hint
【数据规模】
对于30%的测试数据,满足N ≤ 10;
对于60%的测试数据,满足N ≤ 100;
对于80%的测试数据,满足N ≤ 10 000。
对于100%的测试数据,满足N ≤ 1 000 000,每名骑士的战斗力都是不大于 1 000 000的正整数。
对于30%的测试数据,满足N ≤ 10;
对于60%的测试数据,满足N ≤ 100;
对于80%的测试数据,满足N ≤ 10 000。
对于100%的测试数据,满足N ≤ 1 000 000,每名骑士的战斗力都是不大于 1 000 000的正整数。
Solution
n位骑士,每一个人都有一个厌恶对象,可以抽象为n个点n条边的无向图。
抽象的说,就是在一棵树上多加了一条边之后,选出最多的点,使得两两之间没有连边。又因为没有保证图
的连通性,准确的来讲是一片森林。
最简洁的题意:环套树森林最大独立集 (自己都看不懂。。。)
对于一颗环套树,首先找出它的环,这点可以用dfs解决,并且记录好环上相邻的两个节点。我们可以将一个
环断开,那么有且仅有两种不同形态,断开边的u和v有直接边相连和u和v不直接相连。对于每一种形态下的树
我们来一次树形dp,记f[v][0]为不选当前节点的最大值,f[v][1]为选择当前节点后的最大值,ans取较大者
即可。
对于森林结构,枚举每一棵树,将答案累加后就得到了最后输出的结果。
抽象的说,就是在一棵树上多加了一条边之后,选出最多的点,使得两两之间没有连边。又因为没有保证图
的连通性,准确的来讲是一片森林。
最简洁的题意:环套树森林最大独立集 (自己都看不懂。。。)
对于一颗环套树,首先找出它的环,这点可以用dfs解决,并且记录好环上相邻的两个节点。我们可以将一个
环断开,那么有且仅有两种不同形态,断开边的u和v有直接边相连和u和v不直接相连。对于每一种形态下的树
我们来一次树形dp,记f[v][0]为不选当前节点的最大值,f[v][1]为选择当前节点后的最大值,ans取较大者
即可。
对于森林结构,枚举每一棵树,将答案累加后就得到了最后输出的结果。
CODE
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
inline int read(){
char c;int rec=0;
while((c=getchar())<'0'||c>'9');
while(c>='0'&&c<='9')rec=rec*10+c-'0',c=getchar();
return rec;
}
int n;
long long a[1000005];
bool vis[1000005];
struct Branch {int next,to;}branch[2000005];
int h[1000005],cnt=1;
inline void add(int x,int y)
{branch[++cnt].to=y;branch[cnt].next=h[x];h[x]=cnt;return ;}
int P,Q,lim;
long long ans=0;
bool flag[1000005],F;
inline void Dfs_Ring(int v,int pre){
flag[v]=1;vis[v]=1;
for(int i=h[v];i;i=branch[i].next){
int j=branch[i].to;
if(j==pre)continue;
if(flag[j]==1){
lim=i;P=j;Q=v;continue;
}
Dfs_Ring(j,v);
}
}
long long dp[1000005][2];
inline void Dfs_Val(int v,int pre){
dp[v][1]=a[v];dp[v][0]=0;
for(int i=h[v];i;i=branch[i].next){
if(i==lim||i==(lim^1))continue;
int j=branch[i].to;
if(j==pre)continue;
Dfs_Val(j,v);
dp[v][1]+=dp[j][0];
dp[v][0]+=max(dp[j][0],dp[j][1]);
}if(v==Q)dp[v][1]=0;
return ;
}
inline void Sov(int v){
F=0;lim=0;P=v;
Dfs_Ring(v,0);
Dfs_Val(P,0);
long long temp=max(dp[P][0],dp[P][1]);
Q=0;
Dfs_Val(P,0);
temp=max(temp,dp[P][0]);
ans+=temp;
return ;
}
int main(){
n=read();
for(int i=1;i<=n;i++){
a[i]=read();int x=read();
add(i,x);add(x,i);
}
for(int i=1;i<=n;i++){
if(!vis[i])Sov(i);
}cout<<ans;
return 0;
}