这题可以用网络流的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同意,禁止转载,侵权者必究。

posted on 2017-03-19 13:28  Yzyet  阅读(413)  评论(0编辑  收藏  举报