POJ 2226 构造二分图 匹配

虽然二分图模板已然是十分熟悉,但当初练习的时候也只是搜图论列表一个个的练习模板。

话不多说,分析一下这题的构图。

4 4
*.*.
.***
***.
..*.

给定的4*4的图。

要求我们构造木板。每个点的木板可以有横向和纵向两方选择。题中要求选择最少的木板使全部的点都被盖住。

于是乎,构造图就是构造横向铺的木板和纵向的木板,在图中的当前点选择木板的话,就是横向木板和纵向木板之间有边。

1.构造纵向木板

1.4.

.345

234.

..4.

2构造横向木板

1.2.

.333

444.

..5.

然后 用横向木板和纵向木板构造二分图

对横向木板和纵向木板执行匹配

直接使用匈牙利算法即可。


#include<stdio.h>
#include<iostream>
#include<string.h>
#define MAXN 51
using namespace std;

char map[MAXN][MAXN];
int x[MAXN][MAXN];
int y[MAXN][MAXN];
bool ans[MAXN*30][MAXN*30];
bool visited[MAXN*30];
int match[MAXN*30];
int R,C;

bool Match( int pre ,int size )
{
     int i;
     for( i=1;i<=size;i++ )
          if( ans[pre][i] && !visited[i] )
          {
              visited[i]=true;
              if( match[i]==-1 || Match( match[i],size ) )
              {
                  match[i]=pre;
                  return true;
              }
          }
          return false;
}

int main()
{
    while( ~scanf("%d %d",&R,&C ) )
    {
           int i,j;
           for( i=1;i<=R;i++ )
                scanf( "%s",&map[i][0]+1 );
           int sign1=1,sign2=1;
           for( i=1;i<=R;i++ )
                for( j=1;j<=C;j++ )
                {
                     if( map[i][j]=='*' ) x[i][j]=sign1;
                     if(  map[i][j]=='*' && map[i][j+1]!='*' )sign1++;
                }
           
           for( j=1;j<=C;j++ )
                for( i=1;i<=R;i++ )
                {
                     if( map[i][j]=='*' ) y[i][j]=sign2;
                     if( map[i][j]=='*' && map[i+1][j]!='*' )sign2++;
                }

                //printf( "%d %d\n",sign1,sign2 );
           for( i=1;i<=R;i++ )
                for( j=1;j<=C;j++ )
                {
                     if( map[i][j]=='*' )
                     ans[ x[i][j] ][ y[i][j] ]=true;
                }
           int res=0;
           memset( match,-1,sizeof(match) );
           for( i=1;i<=sign1;i++ )
           {
                memset( visited,false,sizeof(visited) );
                if( Match(i,sign2) )
                    res++;
           }
           printf( "%d\n",res );
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值