最小路径覆盖问题

来源:互联网 发布:黑马python基础班视频 编辑:程序博客网 时间:2024/03/28 16:12

问题描述

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

                   V1={x0,x1,,xn}{y0,y1,,yn},
             E1={(x0,xi):iV}{yi,y0:iV}{(xi,yj):(i.j)E}

    每条边的容量均为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 

题解

变态的一道网络流题目,欺骗我感情
好吧,这是一道DAG最短路径覆盖问题。将原来的点进行拆点,对于原来的边(x,y),在网络流图中连接(x0,y1),形成一个二分图,再进行dinic,用节点数n减去所得结果就是路径条数。
为了输出方案,我们可以定义一个数组next,对于每一个节点,我们在dfs的时候记录它的下一个节点,存储到next数组中,最终输出的时候用while循环即可。
到网上膜了一圈,感觉黄学长写得非常清楚,值得参考一下。

CODE:

#include<cstdio>#include<cstring>const int INF=1e9;struct queue{    int h,t;    int a[500];    inline void clear(){h=1,t=0;}    inline void push(int n){a[++t]=n;}    inline int front(){return a[h];}    inline void pop(){h++;}    inline bool empty(){return h>t;}}q;struct edge{    int next,to,remain;}a[20000];int head[500];int deep[500];int next[500];int n,m,S,T,num=1,ans,x,y;inline int min(int a,int b){return a<b?a:b;}inline void add(int x,int y,int cap){    a[++num].next=head[x],a[num].to=y,a[num].remain=cap,head[x]=num;    a[++num].next=head[y],a[num].to=x,head[y]=num;}inline bool bfs(){    memset(deep,0x3f,sizeof(deep));    q.clear(),q.push(S);    deep[S]=0;    while(!q.empty())    {        int tmp=q.front();q.pop();        for(int i=head[tmp];i;i=a[i].next)          if(deep[a[i].to]>INF&&a[i].remain)            q.push(a[i].to),deep[a[i].to]=deep[tmp]+1;    }    return deep[T]<INF;}int dfs(int now,int limit){    if(now==T||!limit) return limit;    int flow=0,f;    for(int i=head[now];i;i=a[i].next)      if(a[i].remain&&deep[a[i].to]==deep[now]+1&&(f=dfs(a[i].to,min(limit,a[i].remain))))      {        next[now]=a[i].to;        flow+=f,limit-=f,a[i].remain-=f,a[i^1].remain+=f;        if(!limit) return flow;      }    deep[now]=-1;    return flow;}inline int dinic(){    int ans=0;    while(bfs()) ans+=dfs(S,INF);    return ans;}void print(int now){    while(next[now])    {        printf("%d ",now);        now=next[now]-n;    }    printf("%d\n",now);}int main(){    scanf("%d%d",&n,&m);    //1~n:顶点 n+1~2*n:拆点 2*n+1:源点 2*n+2:汇点     for(int i=1;i<=m;i++)      scanf("%d%d",&x,&y),add(x,y+n,1);    S=n<<1|1,T=S+1;    for(int i=1;i<=n;i++)      add(S,i,1);    for(int i=1;i<=n;i++)      add(n+i,T,1);    ans=dinic();    for(int i=1;i<=n;i++)      if(!next[n+i]) print(i);    printf("%d",n-ans);    return 0;}
0 0
原创粉丝点击