洛谷2764 最小路径覆盖问题

问题描述:

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

编程任务:

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

Input Format

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

Output Format

从第1 行开始,每行输出一条路径(行末无空格)。文件的最后一行是最少路径数。

 

网络流经典题,网络流24题之一

题意就是在一个有向无环图里,用最少的路径数覆盖每一个点。

就是如果i,j有一条边,就将i和j+n连一条边,跑一下最大匹配

最少路径条数ans=n-最大匹配数

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 10005
#define inf 0x7fffff
int n,m;
int ans;
int cnt=1;
int to[maxn],head[maxn],q[maxn],h[maxn];
bool mark[maxn];
struct edge{
    int next,to,w;
}e[2000005];
void ins(int u,int v,int w){
    cnt++;
    e[cnt].next=head[u];e[cnt].to=v;e[cnt].w=w;
    head[u]=cnt;
}
void insert(int u,int v,int w){
    ins(u,v,w);ins(v,u,0);
}
bool bfs(){
    int t=0,w=1;
    int now;
    memset(h,-1,sizeof h);
    q[0]=h[0]=0;
    while(t<w){
        now=q[t];t++;
        for(int i=head[now];i;i=e[i].next){
            int s=e[i].to;
            if(e[i].w&&h[s]==-1){
                h[s]=h[now]+1;
                q[w++]=s;
            }
        }
    }
    if(h[8001]==-1)return 0;
    return 1;
}
int dfs(int x,int f){
    if(x==8001)return f;
    int w,used=0;
    for(int i=head[x];i;i=e[i].next){
        int s=e[i].to;
        if(e[i].w&&h[s]==h[x]+1){
            w=f-used;
            w=dfs(s,min(w,e[i].w));
            if(w){
                to[x]=s;
                if(s-n>0)mark[s-n]=1;
            }
            e[i].w-=w;
            e[i^1].w+=w;
            used+=w;
            if(used==f)return f;
        }
    }
    if(!used)h[x]=-1;
    return used;
}
void dinic(){
    while(bfs())ans-=dfs(0,inf);
}
int main(){
    scanf("%d%d",&n,&m);
    int x,y;
    for(int i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        insert(x,n+y,inf);
    }
    for(int i=1;i<=n;i++)insert(0,i,1);
    for(int i=1;i<=n;i++)insert(i+n,8001,1);
    ans=n;
    dinic();
    for(int i=1;i<=n;i++){
        if(mark[i])continue;
        int k=i;
        printf("%d ",i);
        while(to[k]){
            printf("%d ",to[k]-n);
            k=to[k]-n;
        }
        printf("\n");
    }
    printf("%d",ans);
}

 

posted @ 2018-01-12 19:51  Elfish?  阅读(232)  评论(0编辑  收藏  举报