线性规划与网络流24题 03最小路径覆盖问题

来源:互联网 发布:加工中心编程软件培训 编辑:程序博客网 时间:2024/06/09 17:51

有向无环图的最小路径覆盖。。。。。。题解中给出的讲解很好了。。。无需解释。。。如果是无向图的话,一样建图,最后最小路径覆盖=|V|-match/2。。。。


【问题分析】


有向无环图最小路径覆盖,可以转化成二分图最大匹配问题,从而用最大流解决。


【建模方法】


构造二分图,把原图每个顶点i拆分成二分图X,Y集合中的两个顶点Xi和Yi。对于原图中存在的每条边


(i,j),在二分图中连接边(Xi,Yj)。然后把二分图最大匹配模型转化为网络流模型,求网络最大流。


最小路径覆盖的条数,就是原图顶点数,减去二分图最大匹配数。沿着匹配边查找,就是一个路径上的


点,输出所有路径即可。


【建模分析】


对于一个路径覆盖,有如下性质:


1、每个顶点属于且只属于一个路径。
2、路径上除终点外,从每个顶点出发只有一条边指向路径上的另一顶点。


所以我们可以把每个顶点理解成两个顶点,一个是出发,一个是目标,建立二分图模型。该二分图的任


何一个匹配方案,都对应了一个路径覆盖方案。如果匹配数为0,那么显然路径数=顶点数。每增加一条


匹配边,那么路径覆盖数就减少一个,所以路径数=顶点数 - 匹配数。要想使路径数最少,则应最大化


匹配数,所以要求二分图的最大匹配。


注意,此建模方法求最小路径覆盖仅适用于有向无环图,如果有环或是无向图,那么有可能求出的一些


环覆盖,而不是路径覆盖。


#include<iostream>#include<cstdio>#include<cstring>using namespace std;#define inf 1<<30#define M 100000#define N 10000#define cc(m,v) memset(m,v,sizeof(m))struct node{    int u,v,f,next;}edge[M];int head[N],p,cur[N],lev[N];int que[M],vis[N];void ainit(){    p=0,cc(head,-1);}bool bfs(int s,int t){    int i,u,v,qin=0,qout=0;    cc(lev,-1),lev[s]=0,que[qin++]=s;    while(qout!=qin){        u=que[qout++];        for(i=head[u];i!=-1;i=edge[i].next)            if(edge[i].f>0 && lev[v=edge[i].v]==-1){                lev[v]=lev[u]+1,que[qin++]=v;                if(v==t) return 1;            }    }    return 0;}int dinic(int s,int t){    int i,f,k,u,qin;    int flow=0;    while(bfs(s,t)){        memcpy(cur,head,sizeof(head));        u=s,qin=0;        while(1){            if(u==t){                for(k=0,f=inf;k<qin;k++)                    if(edge[que[k]].f<f) f=edge[que[i=k]].f;                for(k=0;k<qin;k++)                    edge[que[k]].f-=f,edge[que[k]^1].f+=f;                flow+=f,u=edge[que[qin=i]].u;            }            for(i=cur[u];cur[u]!=-1;i=cur[u]=edge[cur[u]].next)                if(edge[i].f>0 && lev[u]+1==lev[edge[i].v]) break;            if(cur[u]!=-1)                que[qin++]=cur[u],u=edge[cur[u]].v;            else{                if(qin==0) break;                lev[u]=-1,u=edge[que[--qin]].u;            }        }    }    return flow;}void addedge(int u,int v,int f){    edge[p].u=u,edge[p].v=v,edge[p].f=f,edge[p].next=head[u],head[u]=p++;    edge[p].u=v,edge[p].v=u,edge[p].f=0,edge[p].next=head[v],head[v]=p++;}void dfs(int k,int n){    vis[k]=1;    for(int i=head[k];i!=-1;i=edge[i].next)        if(edge[i].f==0 && !vis[edge[i].v] && edge[i].v<=2*n && edge[i].v>=n+1){            printf(" %d",edge[i].v-n);            dfs(edge[i].v-n,n);            return ;        }}int main(){    int n,m,i,ans,u,v;    while(scanf("%d%d",&n,&m)!=-1){        ainit();        for(i=1;i<=n;i++) addedge(0,i,1);        for(i=1;i<=n;i++) addedge(i+n,2*n+1,1);        for(i=1;i<=m;i++){            scanf("%d%d",&u,&v);            addedge(u,v+n,1);        }        ans=n-dinic(0,2*n+1);        cc(vis,0);        for(i=1;i<=n;i++)  if(!vis[i]){            printf("%d",i); dfs(i,n);printf("\n");        }        printf("%d\n",ans);    }    return 0;}


原创粉丝点击