[bzoj1040]: [ZJOI2008]骑士
http://www.lydsy.com/JudgeOnline/problem.php?id=1040
题意:有n个骑士,每个骑士都有一个憎恶的人不能和他同时选,每个骑士有一个战斗力,求最大的战斗力的和
n<=1,000,000 数据范围有点吓人
很明显这是一个无向环带外向树的图。
把环找出来,然后断掉其中的一条边(这样就成了树),分别以这条边的两头为根,并且强制不选另一头,用树形dp算一下答案,取最大值即可。
f[i][0] 表示点i不选的最大战斗力,f[i][1]表示点i选了的战斗力
f[i][1]=sigma(f[v][0]) v是i的儿子
f[i][0]=sigma(max(f[v][0],f[v][1]))
#include<iostream> #include<cstdio> #define ll long long #define MAXN 1000000 using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f; } int s[MAXN+5]; ll f[MAXN+5][2]; int n,rt1,rt2,cnt=1; ll ans=0,maxn; struct edge{ int to,next; }e[MAXN*2+5]; int head[MAXN+5]; bool b[MAXN+5]; bool vis[MAXN+5]; inline void ins(int f,int t) { e[++cnt].next=head[f]; head[f]=cnt; e[cnt].to=t; } void dfs(int x,int fa) { b[x]=1; for(int i=head[x];i&&!rt1;i=e[i].next) { int v=e[i].to; if(v!=fa) { if(b[v]) {rt1=x;rt2=v;e[i].to=e[i^1].to=-1;return;} dfs(v,x); } } } void dp(int x,int fa,int ban) { b[x]=1;if(x!=ban)f[x][1]=s[x];else f[x][1]=0;f[x][0]=0; for(int i=head[x];i;i=e[i].next) { int v=e[i].to; if(v!=-1&&v!=fa) { dp(v,x,ban); f[x][1]+=f[v][0]; f[x][0]+=max(f[v][1],f[v][0]); } } } int main() { n=read(); for(int i=1;i<=n;i++) { s[i]=read();int x=read(); ins(i,x);ins(x,i); } for(int i=1;i<=n;i++) if(!b[i]) { rt1=rt2=0;dfs(i,0); dp(rt1,0,rt2); maxn=max(f[rt1][1],f[rt1][0]); dp(rt2,0,rt1); maxn=max(maxn,max(f[rt2][1],f[rt2][0])); ans+=maxn; } cout<<ans; return 0; }
FallDream代表秋之国向您问好!
欢迎您来我的博客www.cnblogs.com/FallDream