cogs 728. [网络流24题] 最小路径覆盖问题 匈牙利算法

728. [网络流24题] 最小路径覆盖问题

★★★☆   输入文件:path3.in   输出文件:path3.out   评测插件
时间限制:1 s   内存限制:128 MB

 

´问题描述:

 

 

 

 

 

提示:

设V={1,2,...  ,n},构造网络G1=(V1,E1)如下:

 

´编程任务:

 

´数据输入:

 

 

´结果输出:

 

一条路径。文件的最后一行是最少路径数。

 

输入文件示例

 

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

 

 输出文件示例

output.txt

 

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

 

 

 

 

 

 

 

讲解:

Coding!

 

发现自己还是太弱了

这样一道看起来比较简单的二分图最小路径覆盖问题都能出问题 唉

 

现在我们来讲一下这一道题的易错点

1.最小路径覆盖数是  节点数n  -   二分图的最大匹配数

2.这一道题让输出路径  那么这应该怎么办呢?

我想了一个办法是这个样子的

 

首先我们在累加那个ans的时候枚举节点跑匈牙利算法dfs的时候不是从小往大枚举的吗

也就是说那个hav数组 在正常的情况下是hav[后]=hav[前]  但是 如果是这个样子 我们不好输出路径 因为我比较想去从头(较小的)开始输出

 

那么我们再来看一个son数组 和hav数组正好是反过来的

同时我们再设一个in数组 来存储入度

所以经过了上面的处理

 

我们只需要枚举n个点 如果这个点的入度为0   那么我们就从这个点开始  顺着son往后跑 就能打印出该条路径啦

 

 

具体内容看代码理解咯(其实还是比较 简单的  我啰嗦了那么多   还是看代码比较清晰一点啦)

 

鸿篇巨制:

 

#include<bits/stdc++.h>
#define maxn 205
using namespace std;
int n,m;
int vis[maxn],hav[maxn],tim=0;
vector<int> v[maxn];
int in[maxn];
int son[maxn];
bool Dfs(int x)
{
    for(int i=0;i<v[x].size();i++)
    {
        int y=v[x][i];
        if(vis[y]!=tim)
        {
            vis[y]=tim;
            if(!hav[y]||Dfs(hav[y]))
            {
                hav[y]=x;
                son[x]=y;
                in[y]++;
                return true;
            }
        }
    }
    return false;
}
bool Printed[maxn];
void Print(int i)
{
    int x=i;
    while(x!=0)
    {
        printf("%d ",x);
        Printed[x]=true;
        x=son[x];
    }
    putchar('\n');
}
int main()
{
    freopen("path3.in","r",stdin);
    freopen("path3.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1,x,y;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        v[x].push_back(y);
    }
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        tim++;
        ans+=Dfs(i);
    }
    for(int i=1;i<=n;i++)
        if(in[i]==0)
            Print(i);
    printf("%d\n",n-ans);
    return 0;
}

 

点个赞 加个关注再走呗

 

转载于:https://www.cnblogs.com/Tidoblogs/p/11408305.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值