这题可以用网络流的dinic来做,但是只适用于Special Judge,路径有许多方案。
此题的关键在于建图,由于每一个点只能经过一次,我们就考虑到可以用网络流来解决。
首先我们对于每一个点i,再建一个i’点,然后一个超级源点S连向每个i点容量为1的边,在由每个i’点连向超级汇点T容量为1的边,即可。
然后输出路径只需改造一点点即可。
#include<iostream> #include<cstring> #include<cstdio> #include<queue> #include<vector> using namespace std; int getin(){ int num=0,t=1; char c=getchar(); while(c>'9'||c<'0'){if(c=='-')t=-1;c=getchar();} while(c<='9'&&c>='0'){num=num*10+c-'0';c=getchar();} return num*t; } const int maxn=8010; const int INF=0x7fffffff; struct yzy{ int t,c,rev; }; vector<yzy> G[maxn]; int n; void add(int f,int t,int c){ G[f].push_back((yzy){t,c,G[t].size()}); G[t].push_back((yzy){f,0,G[f].size()-1}); } int level[maxn],iter[maxn]; void bfs(int s){ memset(level,0,sizeof(level)); queue<int>q; level[s]=1; q.push(s); while(!q.empty()){ int v=q.front();q.pop(); for(int i=0;i<G[v].size();i++){ yzy &e=G[v][i]; if(e.c>0&&level[e.t]==0){ level[e.t]=level[v]+1; q.push(e.t); } } } } int to[maxn],mark[maxn]; int dfs(int v,int t,int f){ if(v==t)return f; int used=0,d; for(int &i=iter[v];i<G[v].size();i++){ yzy &e=G[v][i]; if(e.c>0&&level[v]+1==level[e.t]){ d=f-used; d=dfs(e.t,t,min(d,e.c)); if(d>0){ to[v]=e.t; //if(v<=n&&e.t>n)cout<<v<<" "<<e.t-n<<"\n"; if(e.t>n)mark[e.t-n]=1; e.c-=d; G[e.t][e.rev].c+=d; used+=d; if(used==f) return f; } } } return used; } int flow(int s,int t){ int flow=0; while(1){ bfs(s); if(level[t]==0)return flow; memset(iter,0,sizeof(iter)); flow+=dfs(s,t,INF); } } int main() { n=getin();int x,y; memset(to,0,sizeof(to)); memset(mark,0,sizeof(mark)); while(scanf("%d%d",&x,&y)!=EOF)add(x,y+n,1); for(int i=1;i<=n;i++) add(0,i,1); for(int i=1;i<=n;i++) add(i+n,n+n+1,1); int ans=n-flow(0,n+n+1); printf("%d\n",ans); for(int i=1;i<=n;i++){ if(mark[i])continue; printf("%d",i); int k=i; while(to[k]){ printf(" %d",to[k]-n); k=to[k]-n; } puts(" 0"); } return 0; }
本文由Yzyet编写,网址为www.cnblogs.com/Yzyet。非Yzyet同意,禁止转载,侵权者必究。