我勒个去怎么这么长。。。。。
求基环森林的最小点覆盖。注意这里是有向的。那么我们考虑加不加多的那条边,对每个连通块dp两遍就行了。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define maxv 1000050 #define inf 1000000007 using namespace std; int n,a[maxv],dx[maxv],dy[maxv],pos[maxv],dp[maxv][3],cnt=0,father[maxv],ans=0; bool flag[maxv]; struct pnt { int id,father,rank; }p[maxv]; struct edge { int x,y,father,root; }e[maxv]; queue <int> q; int read() { char ch;int data=0; while (ch<'0' || ch>'9') ch=getchar(); while (ch>='0' && ch<='9') { data=data*10+ch-'0'; ch=getchar(); } return data; } bool cmp1(pnt x,pnt y) { if (x.father!=y.father) return x.father<y.father; return x.rank<y.rank; } bool cmp2(edge x,edge y) {return x.father<y.father;} int getfather(int x) { if (father[x]==x) return x; father[x]=getfather(father[x]);return father[x]; } void topu_sort() { for (int i=1;i<=n;i++) { if (!dy[i]) q.push(i); p[i].father=getfather(i); } while (!q.empty()) { int head=q.front();q.pop(); dy[a[head]]--;if (!dy[a[head]]) {p[a[head]].rank=p[head].rank+1;q.push(a[head]);} } sort(p+1,p+n+1,cmp1);sort(e+1,e+cnt+1,cmp2); } void tree_dp(int x,int l,int r) { for (int i=l;i<=r;i++) {pos[p[i].id]=inf;flag[p[i].id]=false;dp[p[i].id][1]=dp[p[i].id][2]=0;} int i;dp[0][1]=dp[0][2]=inf; for (i=l;!p[i].rank;i++) { int v=p[i].id; if (v!=x) dp[v][1]=inf;else dp[v][1]=0;dp[v][2]=1; if (v!=a[v]) { if (dp[v][1]<dp[v][2]) {dp[a[v]][1]+=dp[v][1];pos[a[v]]=min(pos[a[v]],dp[v][2]-dp[v][1]);} else {dp[a[v]][1]+=dp[v][2];flag[a[v]]=true;} dp[a[v]][2]+=min(dp[v][1],dp[v][2]); } dp[v][1]=min(dp[v][1],inf);dp[v][2]=min(dp[v][2],inf); } for (;i<=r;i++) { int v=p[i].id; if ((v!=x) && (!flag[v])) dp[v][1]+=pos[v];dp[v][2]++; if (v!=a[v]) { if (dp[v][1]<dp[v][2]) {dp[a[v]][1]+=dp[v][1];pos[a[v]]=min(pos[a[v]],dp[v][2]-dp[v][1]);} else {dp[a[v]][1]+=dp[v][2];flag[a[v]]=true;} dp[a[v]][2]+=min(dp[v][1],dp[v][2]); } dp[v][1]=min(dp[v][1],inf);dp[v][2]=min(dp[v][2],inf); } } int main() { n=read();for (int i=1;i<=n;i++) {father[i]=i;p[i].id=i;} for (int i=1;i<=n;i++) { a[i]=read(); int f1=getfather(i),f2=getfather(a[i]); if (f1==f2) {e[++cnt].x=i;e[cnt].y=a[i];} else {dx[i]++;dy[a[i]]++;father[f1]=f2;} } for (int i=1;i<=cnt;i++) e[i].father=getfather(e[i].x); topu_sort(); int l=1,r=1,ret=0; while (l<=n) { int mn=inf;r=l;while (p[r+1].father==p[l].father) r++; int i;ret++; tree_dp(-1,l,r);mn=min(mn,min(dp[e[ret].x][1],dp[e[ret].y][2])); tree_dp(e[ret].y,l,r);mn=min(mn,dp[e[ret].x][2]); ans+=mn;l=r+1; } printf("%d\n",n-ans); return 0; }