zoukankan      html  css  js  c++  java
  • 【网络流24题】最小路径覆盖问题

    
    

    P1524 - 【网络流24题】最小路径覆盖问题

    Description

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

    Input

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

    Output

    第1行开始,每行输出一条(字典序)路径。最后一行是最少路径数。

    Sample Input

    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

    Sample Output

    1 4 7 10 11
    2 5 8
    3 6 9
    3

    Hint

    数据范围:
    1<=n<=150,1<=m<=6000
    提示:
    设V={1,2,... ,n},构造网络G1=(V1,E1)如下:
    P
    每条边的容量均为1。求网络G1的(x0,y0)最大流。

    Source

    有向无环图最小路径覆盖,网络最大流
    网络流,二分图


    构建二分图,将一个点一分为二,A部一个,B部一个,A部代表前驱,B部代表后继。
    将边连上,从A部到B部,容量为一。
    对于每一条路径,只能有一个入度为0的点和一个出度为0的点,所以路径数=出度为0的点。
    然后虚拟源点和汇点跑最大流,n-最大流就是答案。
    但是还要输出方案。
    当最大流求出来后,整个图上不存在增广路。
    考虑与汇点相连的那些点,在残余网络中,若汇点与某个点之间的返回流量<=0
    则说明这条边的流量为0,即这个点没有作为后继,所以这个点就可以作为路径的起点。
    起点找出来后,就可以一直输出与起点相连的边,直到没有边相连,即这个点没有作为前驱,所以这个点为终点。
     
    
    
     1 #include<set>
     2 #include<map>
     3 #include<queue>
     4 #include<stack>
     5 #include<ctime>
     6 #include<cmath>
     7 #include<string>
     8 #include<vector>
     9 #include<cstdio>
    10 #include<cstdlib>
    11 #include<cstring>
    12 #include<iostream>
    13 #include<algorithm>
    14 using namespace std;
    15 struct data{
    16   int nex,to,w;
    17 }e[20000];
    18 int head[310],lev[310],edge=0,ans[310],n;
    19 void add(int from,int to,int w){
    20   e[++edge].nex=head[from];
    21   e[edge].to=to;
    22   e[edge].w=w;
    23   head[from]=edge;
    24 }
    25 bool bfs(int s,int t){
    26   queue<int>q;
    27   memset(lev,0,sizeof(lev));
    28   q.push(s);lev[s]=1;
    29   while(!q.empty()){
    30     int u=q.front();
    31     q.pop();
    32     for(int i=head[u];i;i=e[i].nex)
    33       if(e[i].w>0 && !lev[e[i].to]){
    34     q.push(e[i].to);
    35     lev[e[i].to]=lev[u]+1;
    36     if(e[i].to==t) return 1;
    37       }
    38   }
    39   return 0;
    40 }
    41 int dfs(int s,int t,int k){
    42   if(s==t) return k;
    43   int tag=0;
    44   for(int i=head[s];i;i=e[i].nex)
    45     if(e[i].w>0 && lev[e[i].to]==lev[s]+1){
    46       int d=dfs(e[i].to,t,min(k-tag,e[i].w));
    47       e[i].w-=d;int op;
    48       if(i%2) op=1;else op=-1;
    49       e[i+op].w+=d;
    50       tag+=d;
    51       if(tag==k) return tag;
    52     }
    53   return tag;
    54 }
    55 int dinic(int s,int t){
    56   int flow=0;
    57   while(bfs(s,t)) flow+=dfs(s,t,1999999999);
    58   return flow;
    59 }
    60 void out(int x){
    61   if(x<=n && x>0) printf("%d ",x);
    62   else return;
    63   for(int i=head[x];i;i=e[i].nex)
    64     if(e[i].w<=0) out(e[i].to-n);
    65 }
    66 int main()
    67 {
    68   freopen("!.in","r",stdin);
    69   freopen("!.out","w",stdout);
    70   int m,x,y;
    71   scanf("%d%d",&n,&m);int s=0,t=2*n+1;
    72   for(int i=1;i<=m;i++)
    73     scanf("%d%d",&x,&y),add(x,y+n,1),add(y+n,x,0);
    74   for(int i=1;i<=n;i++)
    75     add(s,i,1),add(i,s,0),add(i+n,t,1),add(t,i+n,0);
    76   int ans1=n-dinic(s,t);
    77   int kl=0;
    78   for(int i=head[t];i;i=e[i].nex)
    79     if(e[i].w<=0) ans[++kl]=e[i].to-n;
    80   sort(ans+1,ans+1+kl);
    81   for(int i=1;i<=kl;i++)
    82     out(ans[i]),printf("
    ");
    83   printf("%d",ans1);
    84   return 0;
    85 }
    
    

     
     

  • 相关阅读:
    window screen (获取屏幕信息)
    setTimeout 与 setInterval
    php 安装程序
    字符串string 对象发的应用
    数组 array 的方法使用
    angular js h5关于表单验证的例子
    angularjs 路由的应用
    勾选复选框按钮可用否则不可用
    h5正则验证表单
    常见的正则表达式
  • 原文地址:https://www.cnblogs.com/pantakill/p/6603339.html
Copyright © 2011-2022 走看看