本题大意:给出一个n乘n的图,然后给出m个障碍,求是否能用1乘2的长条把图填满。
本题能想到二分图匹配也是不容易,做专项的时候知道是这么个做法才能这样写,1*2,的长条,两个格子是可以相互匹配的,并且只能匹配一起,所以就把一个点与他旁边的四个点连在一起,然后做一次做的二分图匹配,看匹配结果是否与结果相同就可以。
另外提一下二分图匹配,最大匹配次数=最小顶点覆盖
最小路径覆盖=n-最大匹配数
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn=2005;
int dx[4]= {0,0,1,-1};
int dy[4]= {1,-1,0,0};
int n,m,k,is[maxn][maxn],lian[maxn],line[maxn][maxn],used[maxn];
int js(int x,int y)
{
return (x-1)*n+y;
}
int found(int x)//匈牙利模版
{
for(int i=1; i<=m; i++)
for(int j=1; j<=n; j++)
if(line[x][js(i,j)]&&!used[js(i,j)])
{
used[js(i,j)]=1;
if(!lian[js(i,j)]||found(lian[js(i,j)]))
{
lian[js(i,j)]=x;
return 1;
}
}
return 0;
}
void dfs(int x,int y)//建图
{
for(int i=0; i<4; i++)
{
int fx=x+dx[i],fy=y+dy[i];
if(fx>=1&&fx<=m&&fy>=1&&fy<=n&&!is[fx][fy])line[js(x,y)][js(fx,fy)]=1;
}
}
int main()
{
scanf("%d%d%d",&m,&n,&k);
for(int i=1; i<=k; i++)
{
int u,v;
scanf("%d%d",&u,&v);
is[v][u]=1;//是否是障碍物
}
for(int i=1; i<=m; i++)
for(int j=1; j<=n; j++)
if(!is[i][j])
dfs(i,j);//遍历周围四个点
int sum=0;
for(int i=1; i<=m; i++)
for(int j=1; j<=n; j++)
{
memset(used,0,sizeof(used));
if(found(js(i,j)))sum++;
}
if(sum==(m*n-k))printf("YES\n");
else printf("NO\n");
return 0;
}