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

有向无环图的最小路径覆盖。。。。。。题解中给出的讲解很好了。。。无需解释。。。如果是无向图的话,一样建图,最后最小路径覆盖=|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;
}


你可能感兴趣的:(线性规划与网络流24题 03最小路径覆盖问题)