题意: 。。。。
对每行来说, 如果两个*之间没有被#隔开的话, 就把它们看成是一个联通块,因为它们之间只能选一个点, 对列也是这样, 然后对所有*, 在它所属的行块和列块连一条流量为1边, 表示如果选了这个点, 那么它所在的行块和列块都不能选了, 然后从源点向每个行块连边, 并从每个列块向汇点连边, 跑下最大流就行了。
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; #define mnx 55 #define N 3020 #define E 500030 #define inf 0x3f3f3f3f #define ls (i << 1) #define rs (ls | 1) #define md ((ll + rr) >> 1) struct edge { int u, v, cap, flow, nxt; void set(int _u, int _v, int _cap, int _flow, int _nxt) { u = _u, v = _v, cap = _cap, flow = _flow, nxt = _nxt; } }; struct dinic { int s, t, fst[N], cc, d[N], cur[N]; edge e[E]; void init() { memset(fst, -1, sizeof(fst)); cc = 0; } void add(int u, int v, int cap) { e[cc].set(u, v, cap, 0, fst[u]), fst[u] = cc++; e[cc].set(v, u, 0, 0, fst[v]), fst[v] = cc++; } bool bfs() { memset(d, -1, sizeof(d)); queue<int> q; d[s] = 0, q.push(s); while(!q.empty()) { int u = q.front(); q.pop(); for(int i = fst[u]; ~i; i = e[i].nxt) { int v = e[i].v; if(d[v] == -1 && e[i].cap > e[i].flow) { d[v] = d[u] + 1; q.push(v); } } } return d[t] != -1; } int dfs(int x, int a) { if(x == t || a == 0) return a; int f, flow = 0; for(int &i = cur[x]; ~i; i = e[i].nxt) { if(i == inf) i = fst[x]; if(i == -1) break; int v = e[i].v; if(d[v] == d[x] + 1 && (f = dfs(v, min(a, e[i].cap - e[i].flow))) > 0) { a -= f, e[i ^ 1].flow -= f; e[i].flow += f, flow += f; if(!a) break; } } return flow; } int go(int s, int t) { this -> s = s, this -> t = t; int flow = 0; while(bfs()) { memset(cur, 0x3f, sizeof(cur)); flow += dfs(s, inf); } return flow; } }go; int n, m; char g[mnx][mnx]; int id[mnx][mnx]; int S, T; int a, b; bool vis[mnx][mnx]; void getR() { a = 0; memset(vis, 0, sizeof(vis)); for(int i = 1; i <= n; ++i) { for(int j = 1; j <= m; ++j) { if(vis[i][j] || g[i][j] != '*') continue; int k = j; ++a; while(k <= m && g[i][k] != '#') { id[i][k] = a; vis[i][k] = 1; ++k; } } } } void getC() { b = 0; memset(vis, 0, sizeof(vis)); for(int i = 1; i <= m; ++i) { for(int j = 1; j <= n; ++j) { if(vis[j][i] || g[j][i] != '*') continue; int k = j; ++b; while(k <= n && g[k][i] != '#') { vis[k][i] = 1; if(g[k][i] == 'o') { ++k; continue; } go.add(id[k][i], a + b, 1); ++k; } } } } int main() { int cas; scanf("%d", &cas); while(cas--) { go.init(); scanf("%d%d", &n, &m); for(int i = 1; i <= n; ++i) scanf("%s", g[i] + 1); getR(); getC(); S = 0, T = a + b + 1; for(int i = 1; i <= a; ++i) go.add(S, i, 1); for(int i = 1; i <= b; ++i) go.add(i + a, T, 1); printf("%d\n", go.go(S, T)); } return 0; }