1040: [ZJOI2008]骑士
Description
Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英。他们劫富济贫,惩恶扬善,受到社会各
界的赞扬。最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争。战火绵延五百里,在和平环境
中安逸了数百年的Z国又怎能抵挡的住Y国的军队。于是人们把所有的希望都寄托在了骑士团的身上,就像期待有一
个真龙天子的降生,带领正义打败邪恶。骑士团是肯定具有打败邪恶势力的能力的,但是骑士们互相之间往往有一
些矛盾。每个骑士都有且仅有一个自己最厌恶的骑士(当然不是他自己),他是绝对不会与自己最厌恶的人一同出
征的。战火绵延,人民生灵涂炭,组织起一个骑士军团加入战斗刻不容缓!国王交给了你一个艰巨的任务,从所有
的骑士中选出一个骑士军团,使得军团内没有矛盾的两人(不存在一个骑士与他最痛恨的人一同被选入骑士军团的
情况),并且,使得这支骑士军团最具有战斗力。为了描述战斗力,我们将骑士按照1至N编号,给每名骑士一个战
斗力的估计,一个军团的战斗力为所有骑士的战斗力总和。
Input
第一行包含一个正整数N,描述骑士团的人数。接下来N行,每行两个正整数,按顺序描述每一名骑士的战斗力
和他最痛恨的骑士。
Output
应包含一行,包含一个整数,表示你所选出的骑士军团的战斗力。
Sample Input
10 2
20 3
30 1
Sample Output
HINT
N ≤ 1 000 000,每名骑士的战斗力都是不大于 1 000 000的正整数。
看题第一眼是网络流,不过n<1000000,网络流肯定会T。。。然后就学习了一个基环树DP。。
听起来就很高端,实际上也确实如此。。。
考虑一下,如果这个题没有环的话不就是一道树形DP了吗?
设f[x]表示x点去的最大值,g[x]是x点不去的最大值。。
然后转移也很好转移。。。
但是这道题是有环的。。。然后我们考虑把环断开。。。
设环上相邻的两点u,v
如果我们强制u不选,那么v是任意的,那么我们可以以u为根做树形DP,取g[u]..
v同理。。。这样就可以解决了。。。
有一个奇技淫巧是边从2或者0开始编号,i^1是i的反向边,这个比较显然。。。果然是我太弱了。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdlib> 3 #include<cmath> 4 #include<cstring> 5 #include<cstdio> 6 #include<algorithm> 7 #include<string> 8 #include<map> 9 #include<queue> 10 #include<vector> 11 #include<set> 12 #define inf 1000000000 13 #define maxn 1000005 14 #define maxm 1000005 15 #define eps 1e-10 16 #define ll long long 17 #define for0(i,n) for(int i=0;i<=(n);i++) 18 #define for1(i,n) for(int i=1;i<=(n);i++) 19 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 20 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 21 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go) 22 using namespace std; 23 struct edge{ 24 int go,next; 25 }e[maxm*2]; 26 int head[maxn],tot=1; 27 int n,a[maxn],v[maxn],U,V,E; 28 ll f[maxn],g[maxn],ans; 29 int read(){ 30 int x=0,f=1;char ch=getchar(); 31 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 32 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 33 return x*f; 34 } 35 void insert(int u,int v){ 36 e[++tot].go=v;e[tot].next=head[u];head[u]=tot; 37 e[++tot].go=u;e[tot].next=head[v];head[v]=tot; 38 } 39 void dfs(int x,int from){ 40 v[x]=1; 41 for4(i,x){ 42 if((i^1)==from)continue; 43 if(v[y]){ 44 U=x; 45 V=y; 46 E=i; 47 continue; 48 } 49 dfs(y,i); 50 } 51 } 52 void treeDP(int x,int from,int ban){ 53 f[x]=a[x]; 54 g[x]=0; 55 for4(i,x){ 56 if(i==ban||(i^1)==ban||(i^1)==from)continue; 57 treeDP(y,i,ban); 58 f[x]+=g[y]; 59 g[x]+=max(f[y],g[y]); 60 } 61 } 62 int main(){ 63 //freopen("input.txt","r",stdin); 64 //freopen("output.txt","w",stdout); 65 n=read(); 66 for1(i,n){ 67 a[i]=read(); 68 int x=read(); 69 insert(i,x); 70 } 71 for1(i,n) 72 if(!v[i]){ 73 dfs(i,0); 74 treeDP(U,0,E); 75 ll tmp=g[U]; 76 treeDP(V,0,E); 77 ans+=max(tmp,g[V]); 78 } 79 cout<<ans<<endl; 80 return 0; 81 }