poj 2446 二分图最大匹配(奇偶图)网上貌似叫(黑白染色图)

题意:要求用1*2方块完全覆盖除了坑以外的地方,求1*2方块的个数。

思路:如果一个方块的i+j的和 是奇数那么它周围的四个方块,每一个i'+j'的和是偶数;反之相反。所以先把图中所以方块按照,奇数偶数的状态分成两个集合,然后把没有坑的地方的i+j的和是奇数的地方找出来,与周围四个方块(i+j和是偶数)进行建立二分图的边。所以最后求出最大匹配也就求出了1*2方块的总数,最后判断这些方块加上坑的个数能不能拼成原来的图。

#include<iostream>
#define MAX 2000
using namespace std;
int link[MAX];
int flag[MAX][MAX];
bool map[500][500],vis[MAX];
bool g[MAX][MAX];
int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int m,n;
int temp1,temp2;
bool check(int i,int j)
{
  if(!map[i][j]&&i>0&&i<=m&&j>0&&j<=n)//m行 n列 
  return true;
  return false;
}
bool dfs(int u)//奇找偶 
{
  for(int i=1;i<=temp2;i++)
  {
    if(!vis[i]&&g[u][i])
    {
      vis[i]=1;
      if(link[i]==-1||dfs(link[i]))
      {
        link[i]=u;
        return true;
      }
    }
  }
  return false;
}
int maxmatch()
{
  int num=0;
  memset(link,-1,sizeof(link));
  for(int i=1;i<=temp1;i++)//temp1奇数集 
  {
    memset(vis,0,sizeof(vis));
    if(dfs(i))  num++;
  }
  return num;
}
int main()
{
  int k;
  int a,b;
  while(scanf("%d%d%d",&m,&n,&k)!=EOF)
  {
  memset(map,0,sizeof(map));
  for(int i=0;i<k;i++)
  {
    scanf("%d%d",&a,&b);
    map[b][a]=1;
  }
  temp1=temp2=0;
  memset(flag,0,sizeof(flag));
  for(int i=1;i<=m;i++)
    for(int j=1;j<=n;j++)
    {
      if((i+j)%2!=0) flag[i][j]=++temp1;
      else flag[i][j]=++temp2;
    }
    //printf("%d %d\n",temp1,temp2);
    //system("pause");
  memset(g,0,sizeof(g));
  for(int i=1;i<=m;i++)
    for(int j=1;j<=n;j++)
    {
      if((i+j)%2==0||map[i][j]==1) continue;
      for(int t=0;t<4;t++)
      {
        int xx=i+dir[t][0];
        int yy=j+dir[t][1];
        if(check(xx,yy))
        g[flag[i][j]][flag[xx][yy]]=1;
      }
    }
    //printf("%d\n",maxmatch());
    if(m*n==maxmatch()*2+k) printf("YES\n");
    else printf("NO\n");
    //system("pause");
   }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值