• AC日记——最小路径覆盖问题 洛谷 P2764


    题目描述

    «问题描述:

    给定有向图G=(V,E)。设P 是G 的一个简单路(顶点不相交)的集合。如果V 中每个顶点恰好在P 的一条路上,则称P是G 的一个路径覆盖。P 中路径可以从V 的任何一个顶点开始,长度也是任意的,特别地,可以为0。G 的最小路径覆盖是G 的所含路径条数最少的路径覆盖。设计一个有效算法求一个有向无环图G 的最小路径覆盖。提示:设V={1,2,.... ,n},构造网络G1=(V1,E1)如下:

    每条边的容量均为1。求网络G1的( 0 x , 0 y )最大流。

    «编程任务:

    对于给定的给定有向无环图G,编程找出G的一个最小路径覆盖。

    输入输出格式

    输入格式:

    件第1 行有2个正整数n和m。n是给定有向无环图G 的顶点数,m是G 的边数。接下来的m行,每行有2 个正整数i和j,表示一条有向边(i,j)。

    输出格式:

    从第1 行开始,每行输出一条路径。文件的最后一行是最少路径数。

    输入输出样例

    输入样例#1:
    11 12
    1 2
    1 3
    1 4
    2 5
    3 6
    4 7
    5 8
    6 9
    7 10
    8 11
    9 11
    10 11
    输出样例#1:
    1 4 7 10 11
    2 5 8
    3 6 9
    3

    说明

    1<=n<=150,1<=m<=6000

    思路:

      网络流24题之一;

      还是那条性质,求最小割;

      每条有向边的u,v加边都是u,v+n;

      求出最大流,ans=n-最大流;

      然后,我们在求最大流的时候把匹配的点和边做标记以输出路径;

    来,上代码:

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    #define INF 0x7ffffff
    
    using namespace std;
    
    struct EdgeType {
        int to,next,flow;
    };
    struct EdgeType edge[24005];
    
    int if_z,n,m,cnt=1,head[505],s=0,t=504;
    int deep[505],next[505],ans;
    
    bool if_[505];
    
    char Cget;
    
    inline void in(int &now)
    {
        now=0,if_z=1,Cget=getchar();
        while(Cget>'9'||Cget<'0')
        {
            if(Cget=='-') if_z=-1;
            Cget=getchar();
        }
        while(Cget>='0'&&Cget<='9')
        {
            now=now*10+Cget-'0';
            Cget=getchar();
        }
        now*=if_z;
    }
    
    inline void edge_add(int u,int v,int w)
    {
        edge[++cnt].to=v,edge[cnt].flow=w,edge[cnt].next=head[u],head[u]=cnt;
        edge[++cnt].to=u,edge[cnt].flow=0,edge[cnt].next=head[v],head[v]=cnt;
    }
    
    bool BFS()
    {
        queue<int>que;
        memset(deep,-1,sizeof(deep));
        que.push(s),deep[s]=0;
        while(!que.empty())
        {
            int pos=que.front();
            for(int i=head[pos];i;i=edge[i].next)
            {
                if(deep[edge[i].to]<0&&edge[i].flow>0)
                {
                    deep[edge[i].to]=deep[pos]+1;
                    if(edge[i].to==t) return true;
                    que.push(edge[i].to);
                }
            }
            que.pop();
        }
        return false;
    }
    
    int flowing(int now,int flow)
    {
        if(now==t||flow==0) return flow;
        int oldflow=0;
        for(int i=head[now];i;i=edge[i].next)
        {
            if(deep[edge[i].to]!=deep[now]+1||edge[i].flow==0) continue;
            int pos=flowing(edge[i].to,min(flow,edge[i].flow));
            if(pos>0)
            {
                next[now]=edge[i].to;
                if(edge[i].to>n) if_[edge[i].to-n]=true;
            }
            flow-=pos;
            oldflow+=pos;
            edge[i].flow-=pos;
            edge[i^1].flow+=pos;
            if(flow==0) return oldflow;
        }
        return oldflow;
    }
    
    void dinic()
    {
        while(BFS()) ans-=flowing(s,INF);
    }
    
    int main()
    {
        in(n),in(m);int u,v;ans=n;
        for(int i=1;i<=m;i++)
        {
            in(u),in(v);
            edge_add(u,v+n,INF);
        }
        for(int i=1;i<=n;i++)
        {
            edge_add(s,i,1);
            edge_add(i+n,t,1);
        }
        dinic();
        for(int i=1;i<=n;i++)
        {
            if(if_[i]) continue;
            int pos=i;
            printf("%d",pos);
            while(next[pos])
            {
                if(next[pos]>n) next[pos]-=n;
                printf(" %d",next[pos]);
                pos=next[pos];
            }
            printf("
    ");
        }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    JAVA运维总结篇
    python-30个骚操作
    seaweedfs文件存储服务器搭建
    Linux下nginx配置https协议访问
    微信公众平台应用号开发教程
    指导新人的一些心得
    <Android 基础(二十一)> Android 屏幕适配
    Java基础之引用(String,char[],Integer)总结于牛客网的专项练习题
    匿名内部类中关于new Runnable()的使用
    Java中的数据类型转换
  • 原文地址:https://www.cnblogs.com/IUUUUUUUskyyy/p/6440057.html
Copyright © 2020-2023  润新知