题目:http://www.joyoi.cn/problem/tyvj-1940
基环树的样子,看了书上的讲解,准备写树上DP,然后挂了:

#include<iostream> #include<cstdio> #include<cstring> using namespace std; int const MAXN=1e6+5,inf=1e9; int n,a[MAXN],f[MAXN][3],head[MAXN],ct,s[MAXN],h,col[MAXN],cr,rt,ans; int sta[MAXN],top,reg[MAXN]; bool in[MAXN],fl,vis[MAXN]; struct N{ int to,next; N(int t=0,int n=0):to(t),next(n) {} }edge[MAXN]; void add(int x,int y) { edge[++ct]=N(y,head[x]);head[x]=ct; edge[++ct]=N(x,head[y]);head[y]=ct; } void ser(int x) { col[x]=cr; for(int i=head[x],u;i;i=edge[i].next) if(!col[u=edge[i].to])ser(u); } void tj(int rt,int x) { if(fl)return; sta[++top]=x;vis[x]=1; for(int i=head[x],u;i;i=edge[i].next) { if(edge[i].to==a[x])continue; if(!vis[u=edge[i].to])tj(rt,u); else { while(sta[top]!=rt) { int t=sta[top]; s[++h]=t; in[t]=1;top--; } in[rt]=1;s[++h]=rt;top--; fl=1;return; } } top--; } void dfs(int x) { int mn=inf,sum=0; for(int i=head[x],u;i;i=edge[i].next) { u=edge[i].to; if(u==rt)continue; if(u==a[x]||col[u]!=col[x])continue; dfs(u); f[x][0]+=max(f[u][0],f[u][1]); sum+=f[u][1]; mn=min(mn,f[u][1]-f[u][0]); } if(sum==0)f[x][1]=1; else f[x][1]=sum-mn; } void dfs2(int x) { int mn=inf,sum=0; for(int i=head[x],u;i;i=edge[i].next) { u=edge[i].to; if(u==rt)continue; if(u==a[x]||col[u]!=col[x])continue; dfs(u); f[x][0]+=max(f[u][0],f[u][1]); sum+=f[u][1]; mn=min(mn,f[u][1]-f[u][0]); } if(sum==0)f[x][1]=1; else if(x==a[rt])f[x][1]=sum; else f[x][1]=sum-mn; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); reg[i]++;reg[a[i]]++; add(i,a[i]); } for(int i=1;i<=n;i++) { if(!col[i])h=1,cr++,ser(i); int rt;fl=0;int s=0; for(int j=1;j<=n;j++) if(reg[j]>2&&col[j]==cr) {rt=j;break;} tj(rt,i); dfs(rt); s=max(f[rt][1],f[rt][0]); dfs2(rt); s=max(s,f[rt][1]); ans+=s; } printf("%d",ans); return 0; }
题目挺有意思,自己本来也想过贪心的做法,但不会处理链与环交接处的问题,想不清楚一条链会对环有什么影响;
然后看了看别人的博客,才发现链对环没有影响。。。因为环上的点不论链上怎样,仍还有环上别的点限制它;
所以链与环都是隔一个选一个,贪心。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; queue<int>q; int const MAXN=1e6+5; int n,a[MAXN],reg[MAXN],ans; bool vis[MAXN],v2[MAXN]; void bfs() { for(int i=1;i<=n;i++) if(!reg[i])q.push(i); while(q.size()) { int x=q.front();q.pop(); vis[x]=1; if(!vis[a[x]]) { ans++;//因为多起点开始,不方便直接求链的长度,所以一个一个加 vis[a[x]]=1; reg[a[a[x]]]--; if(!reg[a[a[x]]]&&!vis[a[a[x]]]) q.push(a[a[x]]); } } } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); reg[a[i]]++; } bfs(); for(int i=1;i<=n;i++) if(!vis[i]&&!v2[i]) { int cnt=1;v2[i]=1; int j=a[i]; while(!v2[j])cnt++,j=a[j]; ans+=cnt/2; } printf("%d",ans); return 0; }