[9018_1441]最小路径覆盖

题目描述

一个有向无回路的图G=(V,E)的一个路径覆盖是一个其结点不相交的路径集合P,图中的每一个结点仅包含于P中的一条路径。路径可从任意结点开始和结束,且长度也为任意值,包括0。请写出一个有效算法,找出一个包含尽可能少的路径的路径覆盖图中的所有点。
  例如下图至少用两条路径覆盖,路径可以是:1-5-3,2-4。

 

 

输入

输入文件第一行为n(n≤4000),表示图G的顶点个数,从第二行开始每行有两个数u,v表示存在边(u,v)。

输出

输出文件的第一行为所求的最少的路径覆盖数k。第二行至第k+1行为每条路径上以0结尾的顶点序列。

样例输入

5
1 2
1 5
2 3
2 4
5 3

样例输出

2
1 5 3 0
2 4 0


这题可以用匈牙利做,但我介绍一种用FF/dinic做的做法
把每个点拆成2个点,把i到j的连边视为i到j+n,建一个超级源点和超级汇点。跑FF/dinic
路径:找到每条有流量的边,例如(i,j+n),让to【i】等于j,这时,j一定不是开始的点,标号j。
找到每个未标号的点,顺着to找下来
另外,重边真的很烦,因为FF对于重边只会计算第一条读入的边,所以我下面程序取了个min
#include<iostream> 
#include<cstdio> 
#include<vector> 
#include<cstring> 
using namespace std; 
struct edge{ 
    int to,rl,ll,fxb; 
}; 
int n;const int INF=1000000000; 
int x=1;
vector<edge> g[8101]; 
bool used[8101];int ans=0;
int a[100001],b[100001];
int _used[100001],_to[100001],h[4001][4001];
int dfs(int u,int t,int f) 
{ 
    if(u==t)return f; 
    used[u]=1; 
    for(int i=0;i<g[u].size();i++) 
    { 
        edge &e=g[u][i]; 
        if(!used[e.to]&&e.rl>e.ll) 
        { 
            f=min(f,e.rl-e.ll); 
            int d=dfs(e.to,t,f); 
            if(d>0) 
            { 
                e.ll+=d; 
                g[e.to][e.fxb].ll-=d; 
                return d; 
            } 
        } 
    } 
    return 0; 
} 
int flow(int s,int t) 
{ 
    int ff=0; 
    for(;;) 
    { 
        memset(used,0,sizeof(used)); 
        int dd=dfs(s,t,INF); 
        if(dd==0)return ff; 
        ff+=dd; 
    } 
} 
void doing(int x)
{
    if(x==0)return;
    printf("%d ",x);
    doing(_to[x]);
}
int Find()
{
//  for(int i=1;i<x;i++)cout<<a[i]<<" "<<b[i]<<" "<<h[a[i]][b[i]]<<endl;
    for(int i=1;i<x;i++)
    {
        if(g[a[i]][h[a[i]][b[i]]].ll==1 &&!_to[a[i]])
        {
            _to[a[i]]=b[i];
            _used[b[i]]=1;
        }
    }
//  for(int i=1;i<=n;i++)cout<<_to[i]<<" "<<_used[i]<<endl;
    for(int i=1;i<=n;i++)
    {
        if(!_used[i])
        {
            doing(i);printf("0\n");
        }
    }
}
int main() 
{ 
    memset(h,127,sizeof(h));
    scanf("%d",&n);
    while(scanf("%d%d",&a[x],&b[x])!=EOF) 
    {
        int c=g[a[x]].size();
        h[a[x]][b[x]]=min(h[a[x]][b[x]],c);//cout<<h[a[x]][b[x]];
        g[a[x]].push_back(edge{b[x]+n,1,0,g[b[x]+n].size()}); 
        g[b[x]+n].push_back(edge{a[x],0,0,g[a[x]].size()-1}); 
        x++;
    } 
      
    for(int i=1;i<=n;i++) 
    { 
        g[2*n+1].push_back(edge{i,1,0,g[i].size()}); 
        g[i].push_back(edge{2*n+1,0,0,g[2*n+1].size()-1}); 
        g[n+i].push_back(edge{2*n+2,1,0,g[2*n+2].size()}); 
        g[2*n+2].push_back(edge{n+i,0,0,g[n+i].size()-1}); 
    } 
    cout<<n-flow(2*n+1,2*n+2)<<endl; 
    Find();
    return 0; 
} 

 

posted @ 2017-03-13 18:46  lher  阅读(216)  评论(0编辑  收藏  举报