最小路径覆盖问题(网络流,二分图) & 最小路径点覆盖结论证明

最小路径覆盖问题(luogu)

题目描述

 

给定有向图 G=(V,E) 。设 P 是 G 的一个简单路(顶点不相交)的集合。

如果 V 中每个定点恰好在PP的一条路上,则称 P 是 G 的一个路径覆盖。

中路径可以从 V 的任何一个定点开始,长度也是任意的,特别地,可以为 0 。

G 的最小路径覆盖是 G 所含路径条数最少的路径覆盖。设计一个有效算法求一个 GAP (有向无环图) G 的最小路径覆盖。

输入格式

 

第一行有 2 个正整数 n 和 m 。 n 是给定 GAP(有向无环图) G 的顶点数, m 是 G 的边数。

接下来的 m 行,每行有两个正整数 i 和 j 表示一条有向边 (i,j)

输出格式

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

Solution

借此题的多种解法加深对最小路径点覆盖结论的理解

二分图做法

  • 方法一

设最小路径点覆盖的边集为 E

当不考虑图中所有边时 E 中边数为0,最少路径数为 n   

每合法地向 E 中加一条有向边,相当于将两条路径合二为一,最少路径数 - 1

那怎样的边合法呢?

当每个点至多为 E 中一条有向边的起点时, E 合法。

这与二分图中的 “ 1 要素”(每个点至多在一条边中)契合

于是我们将编号为 i 的点分成 i (左部)和 i+n (右部)

对于每条原图中的边,连接(i,j+n)

求答案为 n - 二分图最大匹配

  • 方法二

还是建立方法一中的二分图,求最大匹配,匹配边为放入 E 中的边

此时每个原图中的点最多为一条被选择的原图中边的起点,最多为一条被选择的原图中边的终点

二分图右部的匹配点为一条被选择的原图中边的起点,左部的匹配点为一条被选择的原图中边的终点

考虑右部,每个右部的非匹配点为一条路径的终点,路径条数 = 终点数 = 右部非匹配点数

考虑左部,同理可得到答案

#include <cstdio>
#include <cstdlib>
#include <vector>
using namespace std;
const int N=310,M=6000;
int head[N],tot,ver[M],nxt[M],edge[M];
int n,m,a,b,vis[N],cnt,ans,match[N];
bool flag[N];
vector <int> an;
void add(int x,int y)
{
    ver[++tot]=y,nxt[tot]=head[x],head[x]=tot;
}
bool dfs(int x)
{
    for(int i=head[x],y;i;i=nxt[i])
        if(vis[y=ver[i]]!=cnt)
        {
            vis[y]=cnt;
            if(!match[y] || dfs(match[y]))
            {
                match[y]=x,match[x]=y;
                return 1;
            }
        }
    return 0;
}
int main()
{
    scanf("%d%d",&n,&m);
    while(m--)
    {
        scanf("%d%d",&a,&b);
        add(a,b+n);
    }
    for(int i=1;i<=n;i++)
    {
        cnt++;
        if(dfs(i)) ans++;
    }
    for(int i=1;i<=n;i++)
    {
        if(flag[i]) continue;
        int x=i;
        an.clear();
        while(x>0) flag[x]=true,an.push_back(x),x=match[x]-n;
        int size=an.size();
        for(int i=size-1;i>=0;i--)
            printf("%d ",an[i]);
        puts("");
    }
    printf("%d\n",n-ans);
    return 0;
}
View Code

网络流做法

思路与二分图相似(似乎只是用网络流求二分图最大匹配???)

将编号为 i 的点拆成 i 和 i+n,代表作为一条边起点和终点的情况

i 与源点连一条容量为 1 的边,i+n 与汇点连一条容量为 1 的边,

代表它只能作为一条选中边的起点/终点一次

对于原图中的边(i,j),连建的图中的(i,j+n

通过求最大流求出最多的合法的边

猜你喜欢

转载自www.cnblogs.com/hsez-cyx/p/12353226.html