LOJ 1304 - The Best Contest Site Ever(二分匹配啊)

题目链接:http://lightoj.com/volume_showproblem.php?problem=1304


We are planning to arrange a National Collegiate Programming Contest in Bangladesh. But one of the problems is that members from different teams can discuss with each other if the security is not tight. And this fact sometimes affects the contest rank list. Even if we seize the electronic devices from the team members; there are other ways to communicate. So, our target is to make a site that is fair. The site can be modeled as an M x N grid, where M is the number of rows, and N is the number of columns. Three kinds of cells are there 1) a blank space, 2) a wall, 3) a reserved space. Teams can only be placed in blank spaces, but at most one team can be placed in one blank space. Team members are not allowed to move from their current place, but they can see through the blank or reserved spaces, but not through walls. And they can see vertically or horizontally. To be more specific two members can communicate if they are in the same row (or column) and there is no wall between them in that row (or column) (like a chess rook). As we have already discussed that we don't want members of different teams to communicate, we want to place teams in the grid such that there is no way for the members of two different teams to communicate with each other. So, we are assigning this task to you, providing you the information of the grid, your task is to find the maximum number of teams we can place in the grid, so that we can put extra efforts on the problem set. You have to find a valid placement of teams. As there can be many solutions with maximum number of teams, any valid one will do.

Input

Input starts with an integer T (≤ 100), denoting the number of test cases.

Each case starts with a line containing two integers M (1 ≤ M ≤ 100) and N (1 ≤ N ≤ 100). Each of the next M lines contains N characters denoting the grid. There will be three kinds of characters. A '.' denotes a blank space, a 'W' denotes a wall and an 'R' denotes a reserved space.

Output

For each case, print the case number and the total number of teams in a line. Then print the grid using the same format as in input and report the team cells with 'T'.

Sample Input

Output for Sample Input

2

3 5

.RRR.

WWWWW

.RRR.

3 5

..RR.

.W.RW

.RRR.

Case 1: 2

TRRR.

WWWWW

TRRR.

Case 2: 4

.TRR.

TWTRW

.RRRT

Note

This is a special judge problem, wrong output format may cause 'wrong answer'.



题意:

在一个网格上安排座位,

其中有三种类型:

W:墙壁不能穿过!

。:空白区域,用于放置座位!

R:保留的区域!可以穿过,但是不能放置座位!

座位不能同行或同列,除非有W墙壁隔开,求最多能安排多少座位!

PS:

分块,相同区域(也就是那几块只能放一个座位的记为同一编号!)

这题和ZOJ 1654很类似!题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1654

解题报告:http://blog.csdn.net/u012860063/article/details/47705491

代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
//顶点编号从1开始的
#define MAXN 217
#define MAXM 10017
int LN, RN;//左右集合的数目
//int g[MAXM][MAXM];
int linker[MAXM];
bool used[MAXM];
int head[MAXM];
char ma[MAXN][MAXN];
int num1[MAXN][MAXN], num2[MAXN][MAXN];
struct node
{
    int to;
    int next;
} edge[MAXM];
int cnt = 1;
void addEdge(int u, int v)
{
    edge[cnt].to = v;
    edge[cnt].next = head[u];
    head[u] = cnt++;
}

int dfs(int L)//从左边开始找增广路径
{
    int R;
    //for(R = 1; R <= RN; R++)
    for(int i = head[L]; ~i; i = edge[i].next)
    {
        int R = edge[i].to;
        if(!used[R])
        {
            //找增广路,反向
            used[R] = true;
            if(linker[R] == -1 || dfs(linker[R]))
            {
                linker[R]=L;
                return 1;
            }
        }
    }
    return 0;
}
int hungary()
{
    int res = 0 ;
    int L;
    memset(linker,-1,sizeof(linker));
    for( L = 1; L <= LN; L++)
    {
        memset(used,0,sizeof(used));
        if(dfs(L) != 0)
            res++;
    }
    return res;
}
void init()
{
    memset(edge,0,sizeof(edge));
    memset(head,-1,sizeof(head));
    memset(num1,0,sizeof(num1));
    memset(num2,0,sizeof(num2));
    cnt = 1;
}
int main()
{
    int t;
    int n, m;
    int cas = 0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        init();
        for(int i = 1; i <= n; i++)
        {
            scanf("%s",ma[i]+1);
        }

        int cnt1 = 1, cnt2 = 1;
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= m; j++)
            {
                if(ma[i][j] == '.')
                {
                    num1[i][j] = cnt1;
                }
                else if(ma[i][j] == 'W')
                {
                    cnt1++;
                }
            }
            cnt1++;
        }

        for(int i = 1; i <= m; i++)
        {
            for(int j = 1; j <= n; j++)
            {
                if(ma[j][i] == '.')
                {
                    num2[j][i] = cnt2;
                }
                else if(ma[j][i] == 'W')
                {
                    cnt2++;
                }
            }
            cnt2++;
        }

        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= m; j++)
            {
                if(num1[i][j] && num2[i][j] && ma[i][j]=='.')
                {
                    //g[num1[i][j]][num2[i][j]] = 1;
                    addEdge(num1[i][j], num2[i][j]);
                }
            }
        }
        LN = cnt1;//左右集合
        RN = cnt2;

        int ans = hungary();//最大匹配数
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= m; j++)
            {
                if(ma[i][j]=='.' && linker[num2[i][j]] == num1[i][j])
                {
                    ma[i][j] = 'T';
                }
            }
        }
        printf("Case %d: %d\n",++cas,ans);
        for(int i = 1; i <= n; i++)
        {
            printf("%s\n",ma[i]+1);
        }
    }
    return 0 ;
}
/*
2
3 5
.RRR.
WWWWW
.RRR.
3 5
..RR.
.W.RW
.RRR.
*/


你可能感兴趣的:(二分匹配,LOJ)