这几个图和定义转自https://www.byvoid.com/blog/hungary/
未盖点:设Vi是图G的一个顶点,如果Vi 不与任意一条属于匹配M的边相关联,就称Vi 是一个未盖点。
交错路:设P是图G的一条路,如果P的任意两条相邻的边一定是一条属于M而另一条不属于M,就称P是一条交错路。
可增广路:两个端点都是未盖点的交错路叫做可增广路。
匈牙利算法是用来求最大匹配数的,主要就是找增广路,增广路其实就是虚边-实边-虚边-实边...-虚边这个样子,第一条和最后一条都是虚的,实边连的两个点就是配对的,找增广路就是再找一个不在M中的点,看能不能把路变长或者找到一条匹配的新边。
有两组x,y,用cx,cy数组分别记录x组的节点匹配情况和y组节点匹配情况(cx[i]=j就是x组的第i个点和y组的第j个点匹配,如果没匹配为0)
int augment_path(int u)
{
int v;
for(v=1; v<=q; v++)
if(edge[u][v]&&!vis[v])
{
vis[v]=1;
if(!cy[v]||augment_path(cy[v])) //如果v没匹配或者从v本来对应的x组中的点找到了增广路,u就可以和v匹配
{
cx[u]=v;
cy[v]=u;
return 1;
}
}
return 0;
}
void hungary()
{
memset(cx,0,sizeof(cx));
memset(cy,0,sizeof(cy));
int i;
for(i=1; i<=p; i++)
if(!cx[i]) //如果有未匹配的节点,看能不能从这个点开始找到增广路
{
memset(vis,0,sizeof(vis));
if(augment_path(i)) ans++;
}
}
Alice and Bob often play games on chessboard. One day, Alice draws a board with size M * N. She wants Bob to use a lot of cards with size 1 * 2 to cover the board. However, she thinks it too easy to bob, so she makes some holes on the board (as shown in the figure below).
We call a grid, which doesn’t contain a hole, a normal grid. Bob has to follow the rules below:
1. Any normal grid should be covered with exactly one card.
2. One card should cover exactly 2 normal adjacent grids.
Some examples are given in the figures below:
A VALID solution.
An invalid solution, because the hole of red color is covered with a card.
An invalid solution, because there exists a grid, which is not covered.
Your task is to help Bob to decide whether or not the chessboard can be covered according to the rules above.
![](https://i-blog.csdnimg.cn/blog_migrate/4510260588b39cd59a2e5a79e9306673.jpeg)
We call a grid, which doesn’t contain a hole, a normal grid. Bob has to follow the rules below:
1. Any normal grid should be covered with exactly one card.
2. One card should cover exactly 2 normal adjacent grids.
Some examples are given in the figures below:
![](https://i-blog.csdnimg.cn/blog_migrate/fbad19a66a677c926c13acc9b3c05d88.jpeg)
A VALID solution.
![](https://i-blog.csdnimg.cn/blog_migrate/d48c0b8bae885a1505438acbac2989f3.jpeg)
An invalid solution, because the hole of red color is covered with a card.
![](https://i-blog.csdnimg.cn/blog_migrate/cbda8a0f78ee86f8b8399405d75c16a0.jpeg)
An invalid solution, because there exists a grid, which is not covered.
Your task is to help Bob to decide whether or not the chessboard can be covered according to the rules above.
Input
There are 3 integers in the first line: m, n, k (0 < m, n <= 32, 0 <= K < m * n), the number of rows, column and holes. In the next k lines, there is a pair of integers (x, y) in each line, which represents a hole in the y-th row, the x-th column.
Output
If the board can be covered, output "YES". Otherwise, output "NO".
Sample Input
4 3 2 2 1 3 3
Sample Output
YES
这种棋盘覆盖问题就可以转化为二分图问题了,把棋盘上的相邻的点分为两组,求最大匹配数
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#define INF 0x3f3f3f3f
int M,N,K;
int ans,p,q;
int a[50][50],vis[1000],map[50][50],cx[1000],cy[1000],edge[1000][1000];
int move[4][2]= {-1,0,0,-1,0,1,1,0};
int augment_path(int u)
{
int v;
for(v=1; v<=q; v++)
if(edge[u][v]&&!vis[v])
{
vis[v]=1;
if(!cy[v]||augment_path(cy[v]))
{
cx[u]=v;
cy[v]=u;
return 1;
}
}
return 0;
}
void hungary()
{
memset(cx,0,sizeof(cx));
memset(cy,0,sizeof(cy));
int i;
for(i=1; i<=p; i++)
if(!cx[i])
{
memset(vis,0,sizeof(vis));
if(augment_path(i)) ans++;
}
}
int main()
{
while(scanf("%d%d%d",&M,&N,&K)!=EOF)
{
int i,j,k,m,n,x,y;
ans=0;
p=0;
q=0;
memset(map,0,sizeof(map));
memset(a,0,sizeof(a));
for(i=1; i<=K; i++)
{
scanf("%d%d",&m,&n);
map[n][m]=1;
}
for(i=1; i<=M; i++)
for(j=1; j<=N; j++)
{
if((i+j)%2==0) a[i][j]=++p;
else a[i][j]=++q;
}
for(i=1; i<=M; i++)
for(j=1; j<=N; j++)
if((i+j)%2==0&&!map[i][j])
for(k=0; k<4; k++)
{
x=i+move[k][0];
y=j+move[k][1];
if(x>0&&x<=M&&y>0&&y<=N&&!map[x][y])
{
edge[a[i][j]][a[x][y]]=1;
}
}
hungary();
if(ans*2+K==M*N)
printf("YES\n");
else printf("NO\n");
}
return 0;
}