最小路径覆盖问题(网络流24题之一)

                                                                                    题目

题目描述

«问题描述:

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

每条边的容量均为1。求网络G1的( 0 x , 0 y )最大流。

«编程任务:

对于给定的给定有向无环图G,编程找出G的一个最小路径覆盖。

输入输出格式

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

输出格式:
从第1 行开始,每行输出一条路径。文件的最后一行是最少路径数。

 

这一题还是比较裸的,首先我们要知道:最小路径覆盖=顶点数 - 最大流

然后我们就可以开心地写代码了:

#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int MAXN=1000005;
const int MAXM=1000005;
int d[MAXN],n,m,p[MAXN],eid,S,T,x,y,vis[MAXN];
struct A{
    int v,c,next;
}e[MAXM];
void init(){
    memset(p,-1,sizeof(p));
    eid=0;
}
void add(int u,int v,int c){
    e[eid].v=v;
    e[eid].c=c;
    e[eid].next=p[u];
    p[u]=eid++;
}
void insert(int u,int v,int c){
    add(u,v,c);
    add(v,u,0);
}
int bfs(){
    memset(d,-1,sizeof(d));
    queue<int>q;
    d[S]=0;
    q.push(S);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=p[u];i!=-1;i=e[i].next){
            int v=e[i].v;
            if(e[i].c>0&&d[v]==-1){
                d[v]=d[u]+1;
                q.push(v);	
            }
        }
    }
    return (d[T]!=-1);
}
int dfs(int u,int flow){ 
    if(u==T) return flow;
    int ret=0;
    for(int i=p[u];i!=-1;i=e[i].next){
        int v=e[i].v;
        if(e[i].c>0&&d[v]==d[u]+1){
            int tmp=dfs(v,min(flow,e[i].c));
            e[i].c-=tmp;
            e[i^1].c+=tmp;
            flow-=tmp;
            ret+=tmp;
            if(!flow) break;
        }
    }
    if(!ret) d[u]=-1;
    return ret;
}
int Dinic(){
    int ret=0;
    while(bfs()){
        ret+=dfs(S,INF);
    }
    return ret;
}
void dfss(int x){  // 以下部分码风受YJQ的影响
    if(vis[x]) return;
    vis[x]=1; printf("%d ",x);
    for(int i = p[x]; i + 1; i = e[i].next){
        int v = e[i].v;
        if(!e[i].c && v > n) dfss(v - n);   //因为容量为1,所以为0的肯定是流过的。
    }
}
void print(){
    for(int i = 1; i <= n; i++){
        if(!vis[i]) dfss(i),printf("\n"); 
    }
}
int main () {
    init();
    scanf("%d%d", &n, &m);
    S=0; T=2*n+1;
    for(int i = 1;i <= n; i++) insert(S, i, 1);
    for(int i = 1;i <= n; i++) insert(i + n, T, 1);
    for(int i = 1; i <= m; i++){
        scanf("%d%d", &x, &y);
        insert(x, y + n, 1);
    }
    int ans=n-Dinic();
    print();
    printf("%d",ans);
    return 0;
}

 

(>_<)

 

 

posted @ 2018-07-29 22:46  lahlah  阅读(31)  评论(0编辑  收藏  举报