「HDU5093」 Battle ships 题解

问题

原题链接 HDU5093

Problem Description

Dear contestant, now you are an excellent navy commander, who is responsible of a tough mission currently.

Your fleet unfortunately encountered an enemy fleet near the South Pole where the geographical conditions are negative for both sides. The floating ice and iceberg blocks battleships move which leads to this unexpected engagement highly dangerous, unpredictable and incontrollable.

But, fortunately, as an experienced navy commander, you are able to take opportunity to embattle the ships to maximize the utility of cannons on the battleships before the engagement.

The target is, arrange as many battleships as you can in the map. However, there are three rules so that you cannot do that arbitrary:

A battleship cannot lay on floating ice
A battleship cannot be placed on an iceberg

Two battleships cannot be arranged in the same row or column, unless one or more icebergs are in the middle of them.

Input

There is only one integer T (0<T<12) at the beginning line, which means following T test cases.

For each test case, two integers m and n (1 <= m, n <= 50) are at the first line, represents the number of rows and columns of the battlefield map respectively. Following m lines contains n characters iteratively, each character belongs to one of ‘#’, ‘*’, ‘o’, that symbolize iceberg, ordinary sea and floating ice.

Output

For each case, output just one line, contains a single integer which represents the maximal possible number of battleships can be arranged.

Sample Input

Input
1
2
3
4
5
6
7
8
9
10
11
2
4 4
*ooo
o###
**#*
ooo*
4 4
#***
*#**
**#*
ooo#

Sample Output

Output
1
2
3
5

题目大意

给定一个 #M \times N# 的地图,其中每个位置有三种可能情况:冰山、浮冰和普通海面。现在需要你在普通海面上布置战列舰,每个战列舰上的炮可以覆盖这一格所在的行和列,而冰川会挡住炮,使炮不能覆盖冰川后的地图,求需要多少战列舰才可以火力覆盖整个图。

输入数据一共 TT 组测试数据,每组数据第一行包含 mmnn ,接下来 mm 行,每行包括 nn 个字符, # 表示冰山, * 表示普通海面, o 表示浮冰。

每组数据输出一个数字,表示最少需要多少战列舰才能覆盖地图

1T12,1m,n501 \leq T \leq 12, 1 \leq m, n \leq 50

解题

和 「HDU5087」类似,将边界与冰山或者两冰山之间的海面加浮冰作为一个块点,如果一个列块点与一个行块点有交点,且相交位置为普通海面,则从该行块点向该列块点加一条边,如果这两个点被匹配则表示可以通过在交点位置安排一个战列舰以覆盖这两个块。建图之后对这个二分图进行二分图匹配,则答案就是这个图的最大匹配值。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 52;
char M[MAXN][MAXN];
bool ap[MAXN * MAXN][MAXN * MAXN];
int cntx = 0, cnty = 0;
int result[MAXN * MAXN];
bool use[MAXN * MAXN];
bool dfs(int i) {
if(use[i]) return false;
for(int e = 1; e <= cnty; e++) {
if(!use[e] && ap[i][e]) {
use[e] = true;
if(!result[e] || dfs(result[e])) {
result[e] = i;
return true;
}
}
}
return false;
}
int xiongyali() {
int ans = 0;
memset(result, 0, sizeof(result));
for(int i = 1; i <= cntx; i++) {
memset(use, 0, sizeof(use));
if(dfs(i)) ans++;
}
return ans;
}
int belongx[MAXN][MAXN], belongy[MAXN][MAXN];
inline void init() {
memset(belongx, 0, sizeof(belongx));
memset(belongy, 0, sizeof(belongy));
memset(ap, 0, sizeof(ap));
cntx = cnty = 1;
}
int main() {
int T, n, m;
cin >> T;
for(int t = 1; t <= T; t++) {
cin >> m >> n;
init();
for(int i = 1; i <= m; i++) {
for(int j = 1; j <= n; j++) {
char c;
cin >> c;
M[i][j] = c;
}
}
for(int i = 1; i <= m; i++) {
for(int j = 1; j <= n; j++) {
if(M[i][j] != '#') {
belongx[i][j] = cntx;
}
if(M[i][j] == '#') {
cntx++;
}
}
cntx++;
}
for(int j = 1; j <= n; j++) {
for(int i = 1; i <= m; i++) {
if(M[i][j] != '#') {
belongy[i][j] = cnty;
}
if(M[i][j] == '#') {
cnty++;
}
}
cnty++;
}
for(int i = 1; i <= m; i++) {
for(int j = 1; j <= n; j++) {
if(M[i][j] == '*') {
ap[belongx[i][j]][belongy[i][j]] = true;;
}
}
}
int ans = xiongyali();
cout << ans << endl;
}
return 0;
}