网络流24题 3最小路径覆盖问题(洛谷 P2764)

版权声明:本博客内容基本为原创,如有问题欢迎联系,未经允许请勿转载 https://blog.csdn.net/qq_41955236/article/details/82025190

题目描述

«问题描述:

给定有向图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 行开始,每行输出一条路径。文件的最后一行是最少路径数。

输入输出样例

输入样例#1:

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

输出样例#1:

1 4 7 10 11
2 5 8
3 6 9
3

说明

1<=n<=150,1<=m<=6000


最小路径覆盖=图中点数-最大匹配数。

这道题还有个要找路径的问题,因为点比较少,可以用并查集的思想。


代码如下:

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=205;
int n,m,vis[maxn],match[maxn],now;
vector<int> ve[maxn],veans[maxn];
int ck(int x){
    for(int i=0;i<ve[x].size();i++){
        int v=ve[x][i];
        if(!vis[v]){
            vis[v]=1;
            if(match[v]==0||ck(match[v])){
                match[v]=x;
                return 1;
            }
        }
    }
    return 0;
}
int fin(int x){
    if(!match[x]){
        if(!vis[x]) vis[x]=++now;
        return vis[x];
    }
    return fin(match[x]);
}
int main(){

    scanf("%d%d",&n,&m);
    memset(match,0,sizeof(match));
    int x,y;
    for(int i=0;i<m;i++){
        scanf("%d%d",&x,&y);
        ve[x].push_back(y);
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        memset(vis,0,sizeof(vis));
        if(ck(i)) ans++;
    }
    memset(vis,0,sizeof(vis));
    now=0;
    for(int i=1;i<=n;i++){
        int to=fin(i);
        veans[to].push_back(i);
    }
    for(int i=1;i<=n-ans;i++){
        for(int j=0;j<veans[i].size();j++){
            printf("%d%c",veans[i][j],j==veans[i].size()-1?'\n':' ');
        }
    }
    cout<<n-ans<<endl;
    return 0;
}

   


猜你喜欢

转载自blog.csdn.net/qq_41955236/article/details/82025190