一本通1584骑士
1584:骑士
时间限制: 1000 ms 内存限制: 524288 KB
题目描述
原题来自: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≤104;
对于 100% 的数据,满足 N≤10^6,且每名骑士的战斗力都是不大于 10^6 的正整数。
sol:好难啊qaq,先dfs找到环,删去环上一条边,以删去的边的两个端点为根分别跑dp,加上较大值,再继续对下一个环做同样的操作
#include <bits/stdc++.h> using namespace std; inline int read() { int s=0; bool f=0; char ch=' '; while(!isdigit(ch)) { f|=(ch=='-'); ch=getchar(); } while(isdigit(ch)) { s=(s<<3)+(s<<1)+(ch^48); ch=getchar(); } return (f)?(-s):(s); } #define R(x) x=read() inline void write(long long x) { if(x<0) { putchar('-'); x=-x; } if(x<10) { putchar(x+'0'); return; } write(x/10); putchar((x%10)+'0'); return; } inline void writeln(long long x) { write(x); putchar('\n'); return; } #define W(x) write(x),putchar(' ') #define Wl(x) writeln(x) const int N=1000005,M=2000005; int n,Force[N]; struct Tree { int tot,Next[M],to[M],head[N]; bool Bo[M]; inline void add(int x,int y) { Next[++tot]=head[x]; to[tot]=y; Bo[tot]=1; head[x]=tot; return; } bool Arr[N]; int P1,P2; inline void dfs(int x,int fa) { int i; Arr[x]=1; for(i=head[x];i;i=Next[i]) if(to[i]!=fa) { if(!Arr[to[i]]) { dfs(to[i],x); } else { P1=x; P2=to[i]; } } } long long dp[N][2]; inline void dfs_dp(int x,int fa) { int i; dp[x][1]=Force[x]; dp[x][0]=0; for(i=head[x];i;i=Next[i]) if((to[i]!=fa)&&(Bo[i])) { dfs_dp(to[i],x); dp[x][0]+=max(dp[to[i]][1],dp[to[i]][0]); dp[x][1]+=dp[to[i]][0]; } return; } inline void Solve() { int i,j; long long ans=0; for(i=1;i<=n;i++) if(!Arr[i]) { dfs(i,0); // printf("P1=%d P2=%d\n",P1,P2); for(j=head[P1];j;j=Next[j]) if(to[j]==P2) { Bo[j]=Bo[(j&1)?(j+1):(j-1)]=0; break; } long long S1,S2; dfs_dp(P1,0); S1=dp[P1][0]; dfs_dp(P2,0); S2=dp[P2][0]; // printf("S1=%d S2=%d\n",S1,S2); ans+=max(S1,S2); } Wl(ans); } inline void Init() { tot=0; memset(head,0,sizeof head); return; } }T; int main() { int i; T.Init(); R(n); for(i=1;i<=n;i++) { int x; R(Force[i]); R(x); T.add(i,x); T.add(x,i); } T.Solve(); return 0; } /* input 3 10 2 20 3 30 1 output 30 */
河田は河田、赤木は赤木……。
私は誰ですか。教えてください、私は誰ですか。
そうだ、俺はあきらめない男、三井寿だ!