匈牙利算法用来求解二分图的最大匹配。
设二分图由点集S和点集H组成,v∈S,u∈H。
算法过程:
1.循环S中的点v,看v能否匹配到H中的点。
2.使用dfs在H中寻找v的比配点。
访问H中与v有边的点,若它还没匹配其他的点,那么让它匹配v点,返回匹配成功。
若它已经匹配了其他的点那么看与它匹配的点是否可以和另外的点匹配,若能则让它和v匹配,否则v匹配失败。
(其实就是不断的调整,比如A要和B匹配,但是B已经和C匹配了,那么就看C可不可以再和其他点匹配,若可以,则让C和其他点匹配,这时A就可以和B匹配了)
题目:矩阵游戏
思路:其实这道题很容易想到,只要有N个黑色格子在不同行不同列就可以了,因为只要存在N个这样的格子就可以经过交换行和列的颜色使得这些点出现在主对角线上。然后就dfs做了一下,结果TLE。其实这一题是一个二分图匹配,将行和列看作二分图中的两个点集,让每一行都只能和一列匹配,同样每一列也只能和一行匹配,那么得出的最大匹配数不就是不同行不同列的黑色格子的数目吗。那么如果最大匹配数等于N就可以通过交换使主对角线上的格子变成黑色。
#include<iostream>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<stack>
#include<cmath>
#include<cstring>
#include<algorithm>
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define fori(x,s,t) for(int x=s;x<=t;x++)
#define ford(x,s,t) for(int x=s;x>=t;x--)
#define ll long long
using namespace std;
const int M=220,inf=1e8;
int n,a[M];
bool g[M][M],u[M];
bool dfs(int x)
{
fori(i,1,n)
{
if(g[x][i]&&!u[i])
{
u[i]=1;
if(!a[i]||dfs(a[i]))
{
a[i]=x;
return 1;
}
}
}
return 0;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
fori(i,1,n)
fori(j,1,n)
scanf("%d",&g[i][j]);
int ans=0;
memset(a,0,sizeof(a));
fori(i,1,n)
{
memset(u,0,sizeof(u));
if(dfs(i))ans++;
}
if(ans==n)printf("Yes\n");
else printf("No\n",ans);
}
return 0;
}