创世纪 BZOJ3037 & [Poi2004]SZP BZOJ2068
分析:
树形DP中的一种,基环树DP
针对每一个环跑DP,f[i],g[i]分别表示选或者不选,之后我们注意每次遍历的时候,不要重复遍历。
附上代码:
#include <cstdio> #include <algorithm> #include <cmath> #include <iostream> #include <queue> #include <cstring> #include <cstdlib> using namespace std; #define N 1000005 struct node { int to,next; }e[N<<1]; int head[N],cnt,f[N],g[N],fa[N],now,n,ra[N],rb[N]; void add(int x,int y) { e[cnt].to=y; e[cnt].next=head[x]; head[x]=cnt++; return ; } int find(int x){if(fa[x]==x)return x;return fa[x]=find(fa[x]);} void dfs(int x) { int minn=1<<30; g[x]=0; for(int i=head[x];i!=-1;i=e[i].next) { int to1=e[i].to; if(to1!=now)dfs(to1); g[x]+=max(f[to1],g[to1]); minn=min(minn,max(f[to1],g[to1])-g[to1]); } f[x]=g[x]+1-minn; } int main() { memset(head,-1,sizeof(head)); scanf("%d",&n);int cnt=0; for(int i=1;i<=n;i++)fa[i]=i; for(int i=1;i<=n;i++) { int x; scanf("%d",&x); if(find(x)!=find(i)) { add(x,i); fa[fa[x]]=fa[i]; }else ra[++cnt]=x,rb[cnt]=i; } int ans=0; for(int i=1;i<=cnt;i++) { dfs(ra[i]);now=ra[i]; dfs(rb[i]); int t=f[rb[i]]; f[ra[i]]=g[ra[i]]+1; dfs(rb[i]);ans+=max(t,g[rb[i]]); } printf("%d\n",ans); return 0; }