zoukankan      html  css  js  c++  java
  • [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
    ");
            }
        }
    }
    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; 
    } 
  • 相关阅读:
    51单片机入门(三)
    51单片机入门笔记(二)
    51单片机入门笔记
    团队项目-需求分析报告
    团队项目-选题报告
    第一次结对编程作业
    第一次个人编程作业
    第一次博客作业
    tomcat的安装和配置
    循环
  • 原文地址:https://www.cnblogs.com/lher/p/6544434.html
Copyright © 2011-2022 走看看