• 二分图最大匹配(匈牙利算法)


    题目背景

    二分图

    题目描述

    给定一个二分图,结点个数分别为n,m,边数为e,求二分图最大匹配数

    输入输出格式

    输入格式:

    第一行,n,m,e

    第二至e+1行,每行两个正整数u,v,表示u,v有一条连边

    输出格式:

    共一行,二分图最大匹配

    输入输出样例

    输入样例#1:
    1 1 1
    1 1
    输出样例#1:
    1

    说明

    n,m<=1000,1<=u<=n,1<=v<=m

    因为数据有坑,可能会遇到v>m的情况。请把v>m的数据自觉过滤掉。

    算法:二分图匹配

    增广路定义:从一个未被选中的点出发,依次经过非匹配边,匹配边,非匹配边,匹配边……,

     如果终点是一个未被选择的点,则为增广路。

    这里讲一下我的理解:

       在一个增广路中,非匹配边总比匹配边多一条。那么,对于一种已匹配好的情况,如果

    能找出一条增广路,那么原情况就不是最优的,替换它。如此下去,就能找出二分图的最大匹配。

    所以,对于1……n的点,每次都DFS一下是否有增广路,如果有,答案+1。

       个人感觉这种算法是比较妙的,虽然没有网络流跑的快,但有一定的思维深度(还是画画图更好理解)

    #include<set>
    #include<map>
    #include<queue>
    #include<cmath>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define INF 2147483647
    using namespace std;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int n,m,e,f[2000][2000],link[2000],vis[2000];
    //f表示左右是否有边
    //link[i]表示当前的最大匹配中,右边的i对应的点
    //vis[i]表示当前这个点是否匹配过了,所以要每次都更新
    int dfs(int x){ for(int i=1;i<=m;++i) if(!vis[i]&&f[x][i]){ //注意顺序,常数优化,不然会TLE vis[i]=1; if(!link[i]||dfs(link[i])){ link[i]=x; return 1; } } return 0; } int main(){ n=read();m=read();e=read(); while(e--){ int x,y;x=read();y=read(); f[x][y]=1; } int ans=0; for(int i=1;i<=n;++i){ memset(vis,0,sizeof(vis)); if(dfs(i)) ans++; } printf("%d",ans); return 0; }

    https://www.luogu.org/problem/show?pid=3386

  • 相关阅读:
    eaysui 引用 CSS和JS 文件
    在JSP 页面中 添加CSS 样式
    Spring Hello World
    jsp+jdbc
    eclipse插件开发:使用emf建模型时,需要注意模型的坐标和大小的保存
    eclipse插件开发:GEF 进阶: Viewer
    Asp.net之MsChart控件动态绑定温度曲线图
    根据图中的盲点坐标,弹出div层
    小结get和Post的区别
    使用JavaC编译一个Java文件
  • 原文地址:https://www.cnblogs.com/hanyu20021030/p/6530729.html
Copyright © 2020-2023  润新知