您的位置:首页 > 其它

poj 2446(二分图匹配-通俗易懂)

2018-03-31 13:18 239 查看
题目链接:http://poj.org/problem?id=2446
题目大意:给出一个N*M的棋盘,棋盘有些格子是不能放东西的。现在要判断在所以可以放东西的格子上是否能用1*2的小方块填满
题目思路:
小木块有两个格子,对于棋盘上的每一个格子,如果可以放东西,那么小木块的另一个格子一定在棋盘上这个格子的上下左右。
那么对于整个棋盘,从上到下从左到右给它编号1到n*m,并将每一个格子(如果可以放东西)与其上下左右可以放东西的格子相连~就形成了一个二分图。最后只要最大独立集等于所有顶点数减去最大匹配数,说明就可以放满#include<iostream>
#include<cstring>
#include<cstdio>
#define me(k) memset(k,0,sizeof(k))
using namespace std;
int dir[4][2]={1,0,-1,0,0,1,0,-1};
int a[35][35],m,n;
int map[1100][1100];//用来建立二分用过图
int linker[1100];
bool use[1100];//表示有没有
void build(int x,int y)
{
for(int i=0;i<4;i++)
{
int x1=x+dir[i][0];
int y1=y+dir[i][1];
if(x1>=1&&x1<=m&&y1>=1&&y1<=n&&a[x1][y1]==0)
{
map[(x-1)*n+y][(x1-1)*n+y1]=1;//表示有一条连线
}
}
}
bool dfs(int u)
{
for(int i=1;i<=m*n;i++)
if(map[u][i]&&!use[i])
{
use[i]=true;
if(linker[i]==-1||dfs(linker[i]))
{
linker[i]=u;
return true;
}
}
return false;
}
int hungary()
{
memset(linker,-1,sizeof(linker));
int ans=0;
for(int i=1;i<=n*m;i++)
{
memset(use,false,sizeof(use));
if(dfs(i)) ans++;
}
return ans;
}
int main()
{
int k;
while(~scanf("%d%d%d",&m,&n,&k))
{
me(a);
me(map);
int r,c;
for(int i=1;i<=k;i++)
{
scanf("%d%d",&r,&c);
a[c][r]=1;//表示为坑
}
for(int i=1;i<=m*n;i++)
{
int x=i/n+1;
int y=i%n;
if(y==0) {x--;y=n;}
if(a[x][y]==0)
{
build(x,y);//去建立二分图
}
}
/*for(int i=1;i<=m*n;i++)
{

for(int j=1;j<=m*n;j++)
cout<<map[i][j]<<" ";
cout<<endl;

}*/
int ans=hungary();
// printf("%d\n",ans);
if(ans==n*m-k) printf("YES\n");
else printf("NO\n");

}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: