poj 2446 Chessboard(二分图匹配)

题意:在一个N*M的矩形里,有K个hole 用1*2的木板去覆盖该矩形,每个木板只能覆盖相邻的两个格子,问是否能把每个格子都盖住。

思路:二分匹配。把图中能覆盖的格子从1 依次标号 若格子数为奇数 答案是NO 否则,把相邻的两个标号能连成一条边,求无向图的二分匹配数,当匹配数 == 格子数时,就能覆盖完。如下图
poj <wbr>2446 <wbr>Chessboard(二分图匹配)
标号为:
1 0 2
3 4 5
6 7 0
8 9 10

比如说 4 这个点与 3 5 7 都有边相连。 这题得用边表做,起初用邻接矩阵 狂超时,改边表结构竟0Ms

//248K      0MS
#include <stdio.h>
#include <string.h>
#define Max 1050
#define M 35

int g[M][M],num,n,m,e;
int link[Max],yM[Max],head[Max];
bool vis[Max];

struct E
{
      int to,nxt;
} edge[Max*8];                  //每个点最多与其相邻4个点相连,且为无向图 故为8倍

void addedge(int cu,int cv)
{
      edge[e].to = cv;
      edge[e].nxt = head[cu];
      head[cu] = e ++;
}
void Build (int x,int y)        //建图
{
      if (x-1>0&&g[x-1][y] > 0)
      {
              addedge (g[x-1][y],g[x][y]);
              addedge (g[x][y],g[x-1][y]);
      }
      if (x+1<=n&&g[x+1][y] > 0)
      {
              addedge (g[x+1][y],g[x][y]);
              addedge (g[x][y],g[x+1][y]);
      }
      if (y-1 > 0&&g[x][y-1] > 0)
      {
              addedge (g[x][y-1],g[x][y]);
              addedge (g[x][y],g[x][y-1]);
      }
      if (y +1 <= m&&g[x][y+1] > 0)
      {
              addedge (g[x][y+1],g[x][y]);
              addedge (g[x][y],g[x][y+1]);
      }
}
bool DFS (int u)
{
      for (int i = head[u]; i != -1; i = edge[i].nxt)
      {
              int v = edge[i].to;
              if (!vis[v])
              {
                      vis[v] = true;
                      if (link[v] == -1||DFS(link[v]))
                      {
                              link[v] = u;
                              yM[u] = v;
                              return true;
                      }
              }
      }
      return false;
}
int MaxMatch ()              //匈牙利算法 不用多说了吧
{
      int u,res = 0;
      memset(link,0xFF,sizeof(link));
      memset (yM,0xFF,sizeof(yM));
      for (u = 1; u <= num; u ++)
              if(yM[u] == -1)                //加优化
              {
                      memset (vis,false,sizeof(vis));
                      if (DFS(u))
                              res ++;
              }
      return  res;
}
int main ()
{
      int k,x,y,i,j;
      while (~scanf ("%d%d%d",&n,&m,&k))
      {
              memset (g,0,sizeof(g));
              memset (head,0xFF,sizeof(head));
              e = 0;
              while (k --)
              {
                      scanf ("%d%d",&y,&x);
                      g[x][y] = 1;
              }
              k = 0;
              for (i = 1; i <= n; i ++)
                      for (j = 1; j <= m; j ++)
                              if (g[i][j] == 0)
                                      g[i][j] = ++k;
                              else
                                      g[i][j] = -1;
              num = k;
              if (k%2 == 1)
                      printf ("NO\n");
              else
              {
                      for (i = 1; i <= n; i ++)
                              for (j = 1; j <= m; j ++)
                                      if (g[i][j] > 0)
                                              Build(i,j);
                      if (k == MaxMatch())
                              printf ("%YES\n");
                      else
                              printf ("NO\n");
              }
      }
      return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值