算法自学__匈牙利算法

参考资料:

算法简介

匈牙利算法主要用求二分图的最大匹配最小覆盖

最大匹配问题

问题描述

一种形象的表述:把二分图中的一部分假设为男,另一部分为女,男生和女生之间有暧昧关系,求最大匹配就是求最多能促成多少对情侣。

算法思想

先到先得,能让则让。

代码

// 邻接矩阵存边
bool mat[maxn][maxn];
// vis[i]表示:i号女生是否已经配对
bool vis[maxn];
// p[i]表示:与i号女生配对的男生编号
int p[maxn];

bool match(int i){
    
    
	for(int j=1;j<=n;j++){
    
    
		// 该女生未配对,且这对男女之间有暧昧关系
		if(!vis[j] && mat[i][j]){
    
    
			vis[j] = 1;
			/* match(p[j])表示让之前与i号女生配对的男生
			换匹配对象 */
			if(p[j]==0 || match(p[j])){
    
    
				p[j] = i;
				return true;
			}
		}
	}
	return false;
}

int Hungarian(){
    
    
	int res = 0;
	for(int i=1;i<=n;i++){
    
    
		memset(vis, 0, sizeof(vis));
		// 统计匹配成功的男生数
		if(match(i)) res++;
	}
	return res;
}

例1 P1129 [ZJOI2007] 矩阵游戏

题目大意

给定一个由 01 构成的方阵,可以交换行和列,问能否通过交换操作使得方阵的主对角线上全为 1

思路

将矩阵转化为二分图,一部分代表各行,另一部分代表各列,如果方阵有 mat[i][j] == 1 ,则在行 i 和列 j 之间建立一条边。对这个二分图求最大匹配,如果匹配数恰好等于方阵的行列数 n ,则输出 Yes ,否则输出 No

代码

#include<bits/stdc++.h>
using namespace std;

const int maxn = 205;

int T, n;
bool mat[maxn][maxn];
bool vis[maxn];
int p[maxn];

bool match(int i){
    
    
	for(int j=1;j<=n;j++){
    
    
		if(!vis[j] && mat[i][j]){
    
    
			vis[j] = 1;
			if(p[j]==0 || match(p[j])){
    
    
				p[j] = i;
				return true;
			}
		}
	}
	return false;
}

int Hungarian(){
    
    
	int res = 0;
	for(int i=1;i<=n;i++){
    
    
		memset(vis, 0, sizeof(vis));
		if(match(i)) res++;
	}
	return res;
}

int main(){
    
    
	cin>>T;
	while(T--){
    
    
		cin>>n;
		memset(p, 0, sizeof(p));
		for(int i=1;i<=n;i++){
    
    
			for(int j=1;j<=n;j++){
    
    
				bool a;
				cin>>a;
				if(a) mat[i][j] = 1;
				else mat[i][j] = 0;
			}
		}
		if(Hungarian() == n) cout<<"Yes";
		else cout<<"No";
		cout<<'\n';
	} 
	return 0;
}

最小覆盖问题

问题描述

找到最少的点,删掉所有包含这些点的边,可以删掉所有边。

算法思路

结论:最小覆盖的点数等于最大匹配数。

找到最小覆盖点集的方法:从左侧一个未匹配成功的点出发,走一趟匈牙利算法的流程(即紫色的箭头),所有左侧未经过的点,和右侧经过的点,即组成最小点覆盖。

例1 vijos1204 CoVH之柯南开锁

题目大意

给定一个由 01 构成的 n*m 的矩阵,每次操作可以一行或一列的 1 全部变成 0 。问最少经过多少次操作才能使矩阵全 0

思路

仿照矩阵游戏建立二分图,每次操作等价于删除所有包含该点的边,此时问题就转化成了求二分图的最小覆盖。

代码

略。

猜你喜欢

转载自blog.csdn.net/MaTF_/article/details/129583265