您的位置:首页 > 其它

[BZOJ4554][TJOI2016&HEOI2016]游戏(二分图匹配)

2017-11-19 16:22 471 查看
和[ZJOI2007]矩阵游戏是类似的思想。首先,在上,把连续的不含#的连通块标记出来,如:


上图中用框标出的就是被标记出的连通块。

然后对列上也一样做。然后对于任意一个可以放炸弹的格子,从它所在的行连通块标号向所在的列连通块标号连一条边。然后跑一遍二分图最大匹配,即为答案。

代码:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
inline char get() {
char c; while ((c = getchar()) != '*' && c != 'x' && c != '#');
return c;
}
const int N = 55, M = 2505;
int n, m, tot, ecnt, nxt[M], adj[M], go[M], my[M], row

, col

;
bool vis[M]; char a

;
void add_edge(int u, int v) {
nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v;
}
boo
4000
l dfs(int u) {
for (int e = adj[u], v; e; e = nxt[e])
if (!vis[v = go[e]]) {
vis[v] = 1;
if (!my[v] || dfs(my[v])) {
my[v] = u;
return 1;
}
}
return 0;
}
int solve() {
int i, ans = 0;
for (i = 1; i <= tot; i++) {
memset(vis, 0, sizeof(vis));
if (dfs(i)) ans++;
}
return ans;
}
int main() {
int i, j; n = read(); m = read();
for (i = 1; i <= n; i++) for (j = 1; j <= m; j++)
a[i][j] = get();
for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) {
if (a[i][j] == '#') continue;
if (j == 1 || a[i][j - 1] == '#') tot++;
row[i][j] = tot;
}
for (j = 1; j <= m; j++) for (i = 1; i <= n; i++) {
if (a[i][j] == '#') continue;
if (i == 1 || a[i - 1][j] == '#') tot++;
col[i][j] = tot;
}
for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) {
if (a[i][j] != '*') continue;
add_edge(row[i][j], col[i][j]);
}
printf("%d\n", solve());
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: