Place the Robots zoj 1654

#include <cstdio>
#include <cstring>
#define MAX 51
int m, n;   //地图的大小m*n,(1<= m, n <=50)
char map[MAX][MAX];  //地图
int x[MAX*MAX], y[MAX*MAX];  //x[i]表示与Xi匹配的Y顶点,y[i]表示与Yi匹配的X顶点
int xs[MAX][MAX], ys[MAX][MAX];  //水平方向上"块"的编号,垂直方向上"块"的编号
int xn, yn1;  //水平方向上的"块"个数、垂直方向上的"块"个数
//对水平方向上和垂直方向上的块进行连接(若两个块有公共的空地,则在它们之间连边)
//如果g[i][j]==1,那么水平方向上的第i 个块跟垂直方向上的第j 个块有公共的空地
bool g[MAX*MAX][MAX*MAX];
//DFS算法中记录顶点访问的状态,如果t[i]=0表示未访问过,如果为1表示访问过
int t[MAX*MAX];
//从X集合中的顶点u出发用深度优先策略寻找增广路
//(这种增广路只能使当前的匹配数增加1)
bool path( int u )
{
     int v;
     for( v=1; v<=yn1; v++ )  //考虑所有Yi顶点
     {
          if( g[u][v] && !t[v] )  //v跟u邻接并且v未访问过
          {
               t[v] = 1;
               //如果v没有匹配,
               //或者如果v已经匹配了,但从y[v]出发可以找到一条增广路
               if( !y[v] || path(y[v]) )
               {
                    x[u]=v; y[v]=u; //把v匹配给u, 把u匹配给v
                    return 1;
               }
          }
     }
     return 0; //如果不存在从u出发的增广路
}

void MaxMatch( )  //求二部图的最大匹配算法
{
     int i, ans = 0;  //最大匹配数
     memset( x, 0, sizeof(x) ); memset( y, 0, sizeof(y) );  //从0匹配开始增广
     for( i=1; i<=xn; i++ )
     {
          if( !x[i] ) //从每个未盖点出发进行寻找增广路
          {
               memset( t, 0, sizeof(t) );
               if( path(i) ) //每找到一条增广路,可使得匹配数加1
                    ans++;
          }
     }
     printf( "%d\n", ans );
}

int main( )
{
     int k, kase;//kase的个数
     int i, j;  //循环变量
     int number; //用来对水平方向和垂直方向上的"块"进行编号的序号
     int flag; //一个"块"开始的标志
     scanf( "%d", &kase );
     for( k=0; k<kase; k++ )
     {
          printf( "Case :%d\n", k+1 );
          scanf( "%d%d", &m, &n );  //读入地图大小
          memset( xs, 0, sizeof(xs) );   memset( ys, 0, sizeof(ys) );
          for( i=0; i<m; i++ )  //读入地图
          {
               scanf( "%s", map[i] );
          }
          number = 0; //用来对水平方向和垂直方向上的"块"进行编号的序号
          for( i=0; i<m; i++ )  //对水平方向上的块进行编号
          {
               flag = 0;
               for( j=0; j<n; j++ )
               {
                    if( map[i][j]=='o' )
                    {
                         if( flag==0 ) number++;
                         xs[i][j] = number; flag = 1;
                    }
                    else if( map[i][j]=='#' )   flag = 0;
               }
          }
          xn = number;   number = 0;
          for( j=0; j<n; j++ )  //对垂直方向上的块进行编号
          {
               flag = 0;
               for( i=0; i<m; i++ )
               {
                    if( map[i][j]=='o' )
                    {
                         if( flag==0 ) number++;
                         ys[i][j] = number; flag = 1;
                    }
                    else if( map[i][j]=='#' )   flag = 0;
               }
          }
          yn1 = number;
          memset( g, 0, sizeof(g) );
          for( i=0; i<m; i++ )
          {
               for( j=0; j<n; j++ )
               {
                    //对水平方向上和垂直方向上的块进行连接
                    //(若两个块有公共的空地,则在它们之间连边)
                    if( xs[i][j] ) g[xs[i][j]][ys[i][j]] = 1;
               }
          }
          MaxMatch( );
     }
     return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值