• Cogs 728. [网络流24题] 最小路径覆盖问题


    1. [网络流24题] 最小路径覆盖问题
      ★★☆ 输入文件:path3.in 输出文件:path3.out 评测插件
      时间限制:1 s 内存限制:128 MB
      算法实现题8-3 最小路径覆盖问题(习题8-13)
      ´问题描述:
      给定有向图G=(V,E)。设P是G的一个简单路(顶点不相交)的集合。如果V中每个
      顶点恰好在P的一条路上,则称P是G的一个路径覆盖。P中路径可以从V的任何一个顶
      点开始,长度也是任意的,特别地,可以为0。G的最小路径覆盖是G的所含路径条数最少
      的路径覆盖。
      设计一个有效算法求一个有向无环图G的最小路径覆盖。
      提示:
      设V={1,2,… ,n},构造网络G1=(V1,E1)如下:
      每条边的容量均为1。求网络G1的(x0,y0)最大流。
      ´编程任务:
      对于给定的给定有向无环图G,编程找出G的一个最小路径覆盖。
      ´数据输入:
      由文件input.txt提供输入数据。文件第1行有2个正整数n和m。n是给定有向无环图
      G的顶点数,m是G的边数。接下来的m行,每行有2个正整数i 和j,表示一条有向边(i,j)。
      ´结果输出:
      程序运行结束时,将最小路径覆盖输出到文件output.txt中。从第1行开始,每行输出
      一条路径。文件的最后一行是最少路径数。
      输入文件示例
      input.txt
      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
      输出文件示例
      output.txt
      1 4 7 10 11
      2 5 8
      3 6 9
      3
      数据范围:
      1<=n<=150,1<=m<=6000
    /*
    最小路径覆盖数=V-最大流.
    然后拆点建图.
    搞一个超级源点和汇点跑dinic.
    输出的时候在残余网络里找贡献边.
    恩就是这样. 
    */
    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #define MAXN 10001
    using namespace std;
    struct data{int v,next,c;}e[MAXN*4];
    int n,m,max1=1e9,ans,tot,cut=1,dis[MAXN*2],head[MAXN*2],next[MAXN*2];
    bool in[MAXN*2];
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
        return x*f;
    }
    void add(int u,int v,int x)
    {
        e[++cut].v=v;
        e[cut].c=x;
        e[cut].next=head[u];
        head[u]=cut;
    }
    bool bfs()
    {
        memset(dis,-1,sizeof dis);
        queue<int>q;
        q.push(0);
        dis[0]=0;
        while(!q.empty())
        {
            int u=q.front();q.pop();
            for(int i=head[u];i;i=e[i].next)
            {
                int v=e[i].v;
                if(dis[v]==-1&&e[i].c)
                {
                    dis[v]=dis[u]+1;
                    q.push(v);
                }
            }
        }
        return dis[n*2+1]!=-1;
    }
    int dfs(int u,int y)
    {
        if(u==n*2+1) return y;
        int rest=0;
        for(int i=head[u];i&&rest<y;i=e[i].next)
        {
            int v=e[i].v;
            if(dis[v]==dis[u]+1&&e[i].c)
            {
                int x=dfs(v,min(e[i].c,y-rest));
                rest+=x;
                e[i].c-=x;
                e[i^1].c+=x;
            }
        }
        if(!rest) dis[u]=-1;
        return rest;
    }
    void print()
    {
        for(int u=1;u<=n;u++)
          for(int i=head[u];i;i=e[i].next)
          {
              int v=e[i].v;
              if(e[i].c==max1-1) in[v-n]=true,next[u]=v-n;
          }
        for(int i=1;i<=n;i++)
        {
            int x=i;
            if(!in[x])
            {
                while(x) printf("%d ",x),x=next[x];
                printf("
    ");
            }
        }
    }
    void dinic(int s,int t)
    {
        while(bfs()) ans+=dfs(s,max1);
        print();
        printf("%d
    ",n-ans);
        return ;
    }
    int main()
    {
        freopen("path3.in","r",stdin);
        freopen("path3.out","w",stdout); 
        int x,y;
        n=read(),m=read();
        for(int i=1;i<=n;i++) add(0,i,1),add(i,0,0);
        for(int i=1;i<=n;i++) add(i+n,n*2+1,1),add(2*n+1,i+n,0);
        for(int i=1;i<=m;i++)
        {
            x=read(),y=read();
            add(x,y+n,max1),add(y+n,x,0);
        }
        dinic(0,n*2+1);
        return 0;
    }
  • 相关阅读:
    行内块 块级元素 行内元素
    3种飞翼布局
    emmit
    Linux基础命令
    关于微信小程序下拉出现三个小点
    关于vue,angularjs1,react之间的对比
    微信小程序开发遇见的问题之一
    关于微信小程序的尺寸关系
    关于微信小程序的开发步骤
    关于前端基础知识的一些总结
  • 原文地址:https://www.cnblogs.com/nancheng58/p/10068143.html
Copyright © 2020-2023  润新知