Place the Robots
--------------------------------------------------------------------------------
Time Limit: 5 Seconds Memory Limit: 32768 KB
--------------------------------------------------------------------------------
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 your robots as possible in the map. each robot held a laser weapon which cocould shoot to four direly LY (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 cocould pass the grid of Grass, but cocould not pass the grid of Wall. A robot cocould only be placed in an Empty block. surely the boss wocould 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
O ***
*###
Oo # o
* ** O
4
# Ooo
O # oo
Oo # o
***#
Sample Output
Case: 1
3
Case: 2
5
Given a map of m * n, a map consists of three squares: walls, lawns, and open spaces. It is required to place as many robots as possible in the map. Each robot is equipped with a laser gun and can be shot in four directions (Up, down, left, right) at the same time. The robot remains in the initial square and cannot be moved. Then, it keeps shooting in four directions. Laser shots can penetrate the lawn, but cannot penetrate the walls. Robots can only be placed in open spaces and cannot attack each other. Output the maximum number of robots that can be placed. 'O' indicates the open space, '#' indicates the wall, and '*' indicates the lawn.
Solution: This question is not easy to think about. The key is how to convert it into the biggest matching problem of the two-part graph, that is, how to create a graph.
The following details: the continuous areas that are separated by walls and contain open spaces are called blocks. Obviously, only one robot can be placed in one block. Note: In the same line, if there is no wall between the two open spaces and there is only grass, the two open spaces should belong to the same one ". Similarly, the blocks in the vertical direction are also numbered. Then, we regard each horizontal block as the vertex in vertex set X in the two graphs, and the vertical block as the vertex in set Y. If there is a public space between the two blocks (note, each two blocks can have a maximum of one public space. Because each edge represents a blank space, there must be public vertices between conflicting spaces, the problem is converted to finding the largest edge set without public vertices in the two graphs, that is, finding the maximum matching problem.
See the Code:
# Include <iostream> # include <cstring> # include <string> # include <cmath> # include <cstdio> # include <algorithm> using namespace std; const int MAXN = 55; int n, m; char map [MAXN] [MAXN]; short g [MAXN * MAXN] [MAXN * MAXN]; // The array must not be small, otherwise, WAF may be used directly !! // Use short or bool to avoid MLEint cx [MAXN * MAXN]; int cy [MAXN * MAXN]; struct Point {int br; int bc; Point (): br (-1), bc (-1) {}} s [MAXN * MAXN]; int ha [MAXN] [MAXN]; // auxiliary array bool vis [MAXN * MAXN]; // mark array int sumbr =-1; int sumbc =-1; void init () {memset (ha,-1, sizeof (ha); memset (g, 0, sizeof (g); memset (cx,-1, sizeof (cx); memset (cy,-1, sizeof (cy); sumbr =-1; // record the number of horizontal blocks sumbc =- 1; // record the number of vertical blocks scanf ("% d \ n", & n, & m); int I, j; for (I = 0; I <n; I ++) {scanf ("% s", map [I]) ;}int cnt = 0; int first =-1; for (I = 0; I <n; I ++) // horizontal block label, starting from 0 {first =-1; for (j = 0; j <m; j ++) {if (map [I] [j] = '#') {first =-1;} if (map [I] [j] = 'O ') {if (first =-1) {sumbr ++; first = 1 ;}s [cnt]. br = sumbr; ha [I] [j] = cnt; cnt ++ ;}}for (j = 0; j <m; j + +) // Label the Vertical Block, starting from 0 {first =-1; for (I = 0; I <n; I ++) {if (map [I] [j] = '#') {first =-1;} if (map [I] [j] = 'O ') {if (first =-1) {sumbc ++; first = 1;} int tmp = ha [I] [j]; s [tmp]. bc = sumbc ;}}for (I = 0; I <cnt; I ++) // create a graph {g [s [I]. br] [s [I]. bc] = 1 ;}} int ca = 0; int path (int v) // Hungarian algorithm {int I; for (I = 0; I <= sumbc; I ++) {if (g [v] [I] = 1 &&! Vis [I]) {vis [I] = true; if (cy [I] =-1 | path (cy [I]) {cy [I] = v; cx [v] = I; return 1 ;}}return 0 ;}void solve () {int I; int ans = 0; for (I = 0; I <= sumbr; I ++) {if (cx [I] =-1) {memset (vis, 0, sizeof (vis )); if (path (I) ans ++ ;}} printf ("Case: % d \ n", ++ ca); printf ("% d \ n ", ans);} int main () {int T; scanf ("% d", & T); while (T --) {init (); solve ();} return 0 ;}