• Luogu P2764 最小路径覆盖问题(二分图匹配)


    P2764 最小路径覆盖问题

    题面

    题目描述

    «问题描述:

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

    «编程任务:

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

    输入输出格式

    输入格式:

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

    输出格式:

    从第 (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 4 7 10 11
    2 5 8
    3 6 9
    3
    

    说明

    (1 leq n leq 150,1 leq m leq 6000)

    思路

    “最小路径覆盖大家都会吧?” --老师
    “会啊。” --huyufeifei
    “嗯。” --logeadd

    国庆集训正式开始啦!今天早上讲的是图论。老师打开的 (PPT) 标题为 NOI中的图论算法 ,身为蒟蒻的我还以为老师少打了一个 p ,结果讲了一上午的黑题...我的任务计划变成了上午讲过的题:

    讲到P2304 [NOI2015]小园丁与老司机的时候老师问了上面的那个问题,大家都说会,深深感受到了周围都是神仙的恐惧...我就现在把这题写了。

    说下思路:首先最小路径覆盖的最坏答案就是 (n) ,也就是每个节点都不得不用一条路径去覆盖它。而很容易发现,有边相连的两个点可以用同一路径来覆盖,那么我们就可以把这样的两个点缩到同一条路径之中。能把更多的点缩起来,就能用最少的边达成目的。设我们能缩 (k) 组点,那么最终答案就是 (n-k)

    因为每个点只能缩一次,所以就可以用二分图最大匹配的方法来转换问题,匈牙利算法和最大流都是可行的,在这里我使用的是码量较小的匈牙利。

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN=160;
    const int MAXM=6010;
    int n,m,ans,match[MAXN],inv[MAXN];
    int cnt,top[MAXN],to[MAXM],nex[MAXM];
    int js,edge[MAXN];
    bool vis[MAXN];
    int read()
    {
        int re=0;
        char ch=getchar();
        while(!isdigit(ch)) ch=getchar();
        while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();
        return re;
    }
    bool dfs(int now)
    {
        for(int i=top[now];i;i=nex[i])
        {
            if(!vis[to[i]])
            {
                vis[to[i]]=true;
                if(!match[to[i]]||dfs(match[to[i]]))
                {
                    match[to[i]]=now;
                    inv[now]=to[i];
                    return true;
                }
            }
        }
        return false;
    }
    void fd(int now)
    {
        vis[now]=true,edge[js++]=now;
        if(inv[now]&&!vis[inv[now]]) fd(inv[now]);
        if(match[now]&&!vis[match[now]]) fd(match[now]);
    }
    int main()
    {
        ans=n=read(),m=read();
        while(m--)
        {
            int x=read(),y=read();
            to[++cnt]=y,nex[cnt]=top[x],top[x]=cnt;
        }
        for(int i=1;i<=n;i++)
        {
            memset(vis,0,sizeof vis);
            if(dfs(i)) ans--;
        }
        for(int i=1;i<=n;i++)
        {
            js=0;
            if(!vis[i])
            {
                fd(i);
                sort(edge,edge+js);
                for(int j=0;j<js;j++) printf("%d ",edge[j]);
                puts("");
            }
        }
        printf("%d",ans);
        return 0;
    }
    
  • 相关阅读:
    八个方便C#开发的省时的国外工具
    从babel-polyfill的一个坑而起
    Universal Link
    微信机器人
    微信手记
    Elasticsearch手记
    小游戏引擎手记
    【数学基础】3D数学基础-左右手坐标系
    【linux基础】linux误改sudoers权限之后的恢复及配置sudoers
    【c/c++基础】struct/typedef struct的用法详解总结
  • 原文地址:https://www.cnblogs.com/coder-Uranus/p/9736869.html
Copyright © 2020-2023  润新知