poj 2226 二分图 最小顶点覆盖 “草泥马”

参考地址:http://hi.baidu.com/%BA%A3%CF%E0%C1%AC/blog/item/33dc572f55a1bf4b4fc226a7.html

题意:图中的"*"代表泥泞,"."代表草,要把所以泥泞的地方全铺上板,板可以进行叠加,输出最小的板数。

 一开始看着这道题目,有点儿摸不着头脑,果然像平哥跟龙哥说的那样,这道题的建图模式十分神奇。

      画图画了好久才领略到大牛们的风范。

      例如:

      **...

      *.***

      .****

      .....

      建图的时候先从行开始。相连的那些坑坑洼洼标上相同的数字(有图有真相)

      行:(用数组rr[][]来标识)

         11000

         20333

         04444

         00000

      列:(用数组cc[][]来标识)

         12000

         10456

         03456

         00000

      这就是分开的行列图。不过这里离用匈牙利算法的最小覆盖来解决还差一小步。

      mat[][]数组就是用来标识二分图两边节点的东东。现在转换成mat[rr[i][j]][cc[i][j]]~~这里我之前一直都理解得不是很好,但是画了个图之后,一切都真相大白了。

      画出的图是这样的:

       

     这种行列的构图方式将所有的草地都排除掉了,把坑都连起来的所有可能均建成一个新的图,如上。。太奇妙了……


#include<iostream>
using namespace std;
int r[2500][2500],c[2500][2500];
bool g[2500][2500];
bool vis[2500];
int link[2500];
char S[55][55];
int nx,ny;
bool dfs(int u)
{
  for(int i=1;i<=ny;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<=nx;i++)
  {
    memset(vis,0,sizeof(vis));
    if(dfs(i))  num++;
  }
  return num;
}
int main()
{
  int R,C;
  int  flag; 
  while(scanf("%d%d",&R,&C)!=EOF)
  {
    memset(r,0,sizeof(r));
    memset(c,0,sizeof(c));
    for(int i=0;i<R;i++)
    cin>>S[i];
    nx=0;
    for(int i=0;i<R;i++)
      for(int j=0;j<C;j++)
      {
        if(S[i][j]=='*')
        {
          nx++;
          for(int k=j;S[i][k]=='*';k++)
          {
            r[i][k]=nx;
            j=k;
          }
        }
      }
    ny=0;
    for(int j=0;j<C;j++)
      for(int i=0;i<R;i++)
      {
        if(S[i][j]=='*')
        {
          ny++;
          for(int k=i;S[k][j]=='*';k++)
          {
            c[k][j]=ny;
            i=k;
          }
        }
      }
    for(int i=0;i<R;i++)
      for(int j=0;j<C;j++)
      g[r[i][j]][c[i][j]]=1;
    /*for(int i=0;i<R;i++)
    {
      for(int j=0;j<C;j++)
      printf("%d ",c[i][j]);
      printf("\n");
    } */
    printf("%d\n",maxmatch());//经典构图啊,“草泥马” 
  }
  return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值