ZOJ1654 Place the Robots

Robert is a famous engineer. One day he was given a task by his boss. The background of the task was the following:

Given a map consisting of square blocks. There were three kinds of blocks: Wall, Grass, and Empty. His boss wanted to place as many robots as possible in the map. Each robot held a laser weapon which could shoot to four directions (north, east, south, west) simultaneously. A robot had to stay at the block where it was initially placed all the time and to keep firing all the time. The laser beams certainly could pass the grid of Grass, but could not pass the grid of Wall. A robot could only be placed in an Empty block. Surely the boss would not want to see one robot hurting another. In other words, two robots must not be placed in one line (horizontally or vertically) unless there is a Wall between them.

Now that you are such a smart programmer and one of Robert's best friends, He is asking you to help him solving this problem. That is, given the description of a map, compute the maximum number of robots that can be placed in the map.


Input


The first line contains an integer T (<= 11) which is the number of test cases. 

For each test case, the first line contains two integers m and n (1<= m, n <=50) which are the row and column sizes of the map. Then m lines follow, each contains n characters of '#', '*', or 'o' which represent Wall, Grass, and Empty, respectively.


Output

For each test case, first output the case number in one line, in the format: "Case :id" where id is the test case number, counting from 1. In the second line just output the maximum number of robots that can be placed in that map.


Sample Input

2
4 4
o***
*###
oo#o
***o
4 4
#ooo
o#oo
oo#o
***#


Sample Output

Case :1
3
Case :2

5


#include <iostream>
#include<cstdio>
#include<cstring>
#define Max 51
using namespace std;
int m,n;//地图的大小m*n
char map[Max][Max];//地图
//x[i]表示与Xi匹配的Y的顶点
int x[Max*Max],y[Max*Max];
int xs[Max][Max],ys[Max][Max];//水平方向上块的编号,垂直方向上块的编号
int xn,yn;//水平方向上块的个数
//对水平方向与垂直方向上的块进行连接(若两个块有公共空地,则在它们之间连边)
//如果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<=yn;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;
                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;
    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));
        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;
            }
        }
        yn=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、付费专栏及课程。

余额充值