【bzoj4554】[Tjoi2016&Heoi2016]游戏
*题目描述:
在2016年,佳缘姐姐喜欢上了一款游戏,叫做泡泡堂。简单的说,这个游戏就是在一张地图上放上若干个炸弹,看
是否能炸到对手,或者躲开对手的炸弹。在玩游戏的过程中,小H想到了这样一个问题:当给定一张地图,在这张
地图上最多能放上多少个炸弹能使得任意两个炸弹之间不会互相炸到。炸弹能炸到的范围是该炸弹所在的一行和一
列,炸弹的威力可以穿透软石头,但是不能穿透硬石头。给定一张n*m的网格地图:其中*代表空地,炸弹的威力可
以穿透,可以在空地上放置一枚炸弹。x代表软石头,炸弹的威力可以穿透,不能在此放置炸弹。#代表硬石头,炸
弹的威力是不能穿透的,不能在此放置炸弹。例如:给出1*4的网格地图*xx*,这个地图上最多只能放置一个炸弹
。给出另一个1*4的网格地图*x#*,这个地图最多能放置两个炸弹。现在小H任意给出一张n*m的网格地图,问你最
多能放置多少炸弹
*输入:
第一行输入两个正整数n,m,n表示地图的行数,m表示地图的列数。1≤n,m≤50。接下来输入n行m列个字符,代表网
格地图。*的个数不超过n*m个
*输出:
输出一个整数a,表示最多能放置炸弹的个数
*样例输入:
4 4
#***
*#**
**#*
xxx#
*样例输出:
5
*题解:
每一行和每一列的每一个联通块建成一个点,然后每一个空地建成一条连接两个点的边,然后答案就是二分图的最大匹配。
*代码:
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #ifdef WIN32 #define LL "%I64d" #else #define LL "%lld" #endif #ifdef CT #define debug(...) printf(__VA_ARGS__) #define setfile() #else #define debug(...) #define filename "" #define setfile() freopen(filename".in", "r", stdin); freopen(filename".out", "w", stdout); #endif #define R register #define getc() (S == T && (T = (S = B) + fread(B, 1, 1 << 15, stdin), S == T) ? EOF : *S++) #define dmax(_a, _b) ((_a) > (_b) ? (_a) : (_b)) #define dmin(_a, _b) ((_a) < (_b) ? (_a) : (_b)) #define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0) #define cmin(_a, _b) (_a > (_b) ? _a = (_b) : 0) char B[1 << 15], *S = B, *T = B; inline int FastIn() { R char ch; R int cnt = 0; R bool minus = 0; while (ch = getc(), (ch < '0' || ch > '9') && ch != '-') ; ch == '-' ? minus = 1 : cnt = ch - '0'; while (ch = getc(), ch >= '0' && ch <= '9') cnt = cnt * 10 + ch - '0'; return minus ? -cnt : cnt; } #define maxn 3000 #define maxm 20000 char mp[60][60]; int id[60][60]; struct Edge { Edge *next, *rev; int to, w; }*last[maxn], *cur[maxn], e[maxm], *ecnt = e; inline void link(R int a, R int b, R int w) { *++ecnt = (Edge) {last[a], ecnt + 1, b, w}; last[a] = ecnt; *++ecnt = (Edge) {last[b], ecnt - 1, a, 0}; last[b] = ecnt; } int dep[maxn], s, t; std::queue<int> q; inline bool bfs() { q.push(t); memset(dep, -1, sizeof(dep)); dep[t] = 0; while (!q.empty()) { R int now = q.front(); q.pop(); for (R Edge *iter = last[now]; iter; iter = iter -> next) { R int pre = iter -> to; if (iter -> rev -> w && dep[pre] == -1) { dep[pre] = dep[now] + 1; q.push(pre); } } } return dep[s] != -1; } int dfs(R int x, int f) { if (x == t) return f; R int used = 0; for (R Edge* & iter = cur[x]; iter; iter = iter -> next) { R int pre = iter -> to; if (iter -> w && (dep[pre] + 1 == dep[x])) { R int v = dfs(pre, dmin(iter -> w, f - used)); iter -> w -= v; iter -> rev -> w += v; used += v; if (used == f) return f; } } if (!used) dep[x] = -1; return used; } int ans; #define inf 0x7fffffff inline void dinic() { while (bfs()) { memcpy(cur, last, sizeof(last)); ans += dfs(s, inf); } } int main() { // setfile(); R int n = FastIn(), m = FastIn(); for (R int i = 1; i <= n; ++i) { for (R int j = 1; j <= m; ++j) mp[i][j] = getc(); getc(); } R int tot1 = 1; s = 0; t = 2333; for (R int i = 1; i <= n; ++i) { for (R int j = 1; j <= m; ++j) { if (mp[i][j] == '#') ++tot1; id[i][j] = tot1; } ++tot1; } R int tot2 = tot1 + 1; for (R int j = 1; j <= m; ++j) { for (R int i = 1; i <= n; ++i) { if (mp[i][j] == '#') ++tot2; else if (mp[i][j] == '*') link(id[i][j], tot2, 1); } ++tot2; } t = tot2 + 1; for (R int i = 1; i <= tot1; ++i) link(s, i, 1); for (R int i = tot1 + 1; i <= tot2; ++i) link(i, t, 1); dinic(); printf("%d\n", ans ); return 0; }