P2607 [ZJOI2008]骑士
【题意】
有 N 个骑士,每个骑士有且仅有一个厌恶的骑士(不会是他自己),每个骑士都有一个战斗力,现要求从中选取一些骑士,使得这 N 个骑士之间相互不厌恶的同时,其战斗力之和最大,输出这个最大的战斗力之和
【分析】
这题是基环树森林求最大权独立集
P1453 城市环路 的升级版直接对于每个基环树计算即可,答案累加
唯一就是找环稍微麻烦了一点
【代码】
#include<bits/stdc++.h> using namespace std; const int maxn=2e6+5; const long long inf=1e17; int n,root,cnt,v[maxn],fa[maxn],vis[maxn],head[maxn]; long long f[maxn][2]; struct edge { int to,nxt; }e[maxn]; void add(int x,int y) { e[++cnt].to=y; e[cnt].nxt=head[x]; head[x]=cnt; } long long ans; void dfs(int x) { vis[x]=1; f[x][1]=v[x]; f[x][0]=0; for(int i=head[x];i;i=e[i].nxt) { int to=e[i].to; if(to==root) { f[to][1]=-inf; continue; } dfs(to); f[x][0]+=max(f[to][0],f[to][1]); f[x][1]+=f[to][0]; } } void circle(int x) { vis[x]=1; root=x; while(!vis[fa[root]]) { root=fa[root]; vis[root]=1; } dfs(root); long long ans1=max(f[root][0],f[root][1]); vis[root]=1; root=fa[root]; dfs(root); long long ans2=max(f[root][0],f[root][1]); ans+=max(ans1,ans2); } int main() { // freopen("a.in","r",stdin); // freopen("a.out","w",stdout); scanf("%d",&n); int x; for(int i=1;i<=n;i++) { scanf("%d%d",&v[i],&x); add(x,i); fa[i]=x; } for(int i=1;i<=n;i++) if(!vis[i]) circle(i); printf("%lld",ans); return 0; }