POJ3041 二分图的最小覆盖问题——匈牙利算法

POJ3041 二分图的最小覆盖点问题——匈牙利算法

光是完全理解算法就花了几天时间。。基础还是太差了。。后悔大一没好好听课

算法背景

https://blog.csdn.net/jeryjeryjery/article/details/79596922

https://blog.csdn.net/qq_25379821/article/details/83721379

https://cloud.tencent.com/developer/article/1346205

最小覆盖数==最大匹配数,因此先从最大匹配问题开始分析:

朴素的递归思想比较容易理解:一句话,能让别人让就让。

如何从增广路径的角度去考虑,不好理解。在寻找增广路径时,“能让别人让就让”反映为被匹配的那个节点没有和其它人已匹配或者和该节点匹配的其他人能找到人匹配(按照递归的写法若该节点被判断为可以匹配,事实上增广路径此时已经找到,这种写法等价于深度优先地搜索一条交替路,而跳出递归的条件恰恰是这条交替路成为了增广路,在回溯的过程中会完成一系列“反色”操作,匹配数加一,同时起始的未匹配点也完成了匹配),下面要做的就是遍历所有的增广路,每找到一条新的增广路匹配数就会加一。因为一个未匹配点为起点对应的增广路只有一条(结合“能让别人让就让”来思考,一个未匹配点作为起点一次的话,“反色”后就会变成匹配点,而根据增广路的寻找规则,即使接下来再有其他增广路途经这个点,这个点也不会变成未匹配点,自然也不会再作为起点),再加上二分图的匹配实际上是一一对应的,所以只需对数量较少的那个部的所有点进行一次寻找增广路操作,此时就已经找到了最大匹配。

在增广路的寻找过程中,深搜和广搜的效率是接近的,但是深搜更好理解一些。邻接矩阵的复杂度要比邻接表高。

核心代码

bool dfs(int u) {
	for (int v = 0; v < vN; v++) {
		if (g[u][v] && !used[v]) {//匹配到第一个空闲的节点,其实就是深搜的标准操作
			used[v] = true;
			if (linker[v] == -1 || dfs(linker[v])) {//被匹配的那个节点没有和其它人已匹配或者和该节点匹配的其他人能找到人匹配
				linker[v] = u;
				return true;
			}
		}
	}
	return false;
}

对vis数组的理解

跳出递归有两种可能:return false 或者是 return true。return false的话意味着这条尝试找到的增广路失败了,但是一路走来没有改变任何匹配关系(要改变的话一定要return true,因此这个vis实际上完成了两个功能:保证当前尝试的路径上的所有点下次再寻找时都不会再次找到,一是防止死循环,二是避免了重复的无谓劳动);return true的话找到了增广路,可以直接下班了。(之前老是觉得有可能中途某个节点的可匹配性可以改变,因此不能理解,其实只要每个节点遍历一次就好了

题目分析

http://poj.org/problem?id=3041

https://www.jianshu.com/p/b4c5fb3439d4

本题将行与列视为点,每个障碍物点视为边,问题转化为求一个最小覆盖。

代码

#include<iostream>
#include<string.h>
using namespace std;

const int MAXN = 550;

int N,K,R,C;
int mat[MAXN][MAXN],vis[MAXN],match[MAXN];


int dfs(int x){
    for(int i = 1;i <= N;i++){
        if(mat[x][i] && !vis[i]){
            vis[i] = 1;
            if(match[i]==-1||dfs(match[i])){
                match[i] = x;
                return 1;
            }
        }
    }
    return 0;
}

int main(){
    cin>>N>>K;
    memset(mat,0,sizeof(mat));
    memset(match,-1,sizeof(match));
    for(int i = 0;i < K;i++){
        cin>>R>>C;
        mat[R][C] = 1;
    }

    int cnt = 0;
    for(int i = 1;i <= N;i++){
        memset(vis,0,sizeof(vis));
        if(dfs(i)) cnt++;
    }
    cout<<cnt;
}

1840K 63MS

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕业设计,基于SpringBoot+Vue+MySQL开发的纺织品企业财务管理系统,源码+数据库+毕业论文+视频演示 在如今社会上,关于信息上面的处理,没有任何一个企业或者个人会忽视,如何让信息急速传递,并且归档储存查询,采用之前的纸张记录模式已经不符合当前使用要求了。所以,对纺织品企业财务信息管理的提升,也为了对纺织品企业财务信息进行更好的维护,纺织品企业财务管理系统的出现就变得水到渠成不可缺少。通过对纺织品企业财务管理系统的开发,不仅仅可以学以致用,让学到的知识变成成果出现,也强化了知识记忆,扩大了知识储备,是提升自我的一种很好的方法。通过具体的开发,对整个软件开发的过程熟练掌握,不论是前期的设计,还是后续的编码测试,都有了很深刻的认知。 纺织品企业财务管理系统通过MySQL数据库与Spring Boot框架进行开发,纺织品企业财务管理系统能够实现对财务人员,员工,收费信息,支出信息,薪资信息,留言信息,报销信息等信息的管理。 通过纺织品企业财务管理系统对相关信息的处理,让信息处理变的更加的系统,更加的规范,这是一个必然的结果。已经处理好的信息,不管是用来查找,还是分析,在效率上都会成倍的提高,让计算机变得更加符合生产需要,变成人们不可缺少的一种信息处理工具,实现了绿色办公,节省社会资源,为环境保护也做了力所能及的贡献。 关键字:纺织品企业财务管理系统,薪资信息,报销信息;SpringBoot
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值