CF1404E
考虑每个 # 的位置使用一块木板,之后进行一些调整。
对于每次调整,我们合并两块木板,使得合并完后木板依旧合法。
这个合并的过程考虑使用二分图的最大独立集。
具体的,我们把相邻的两个 # 之间连边,把边看做新图上的点。对于新图上的点 $u1$(假设它在原图上的对应边为 $l1$),它在新图上会和一个点 $u2$ 连边当且仅当 $u2$ 在原图上对应的边与 $l1$ 有交点。会发现这样的限制组成了一张二分图——原图中上下相连的边只会与左右相连的边建边。跑二分图的最大独立集即可($\text{二分图的最大独立集}=n-\text{最大匹配}$)。
#include <bits/stdc++.h>
#define FL(i, a, b) for(int i = (a); i <= (b); i++)
#define FR(i, a, b) for(int i = (a); i >= (b); i--)
using namespace std;
typedef long long ll;
const int S = 210, N = 80010, M = 320010;
const ll INF = 1e18;
struct E{int v; ll w, nxt;} e[M << 1];
int n, m, s, t, cnt, tot, tote, head[N], now[N], dep[N], e1[S][S], e2[S][S];
char mp[S][S];
void Adde(int u, int v, ll w){
e[tote] = {v, w, head[u]}, head[u] = tote++;
}
int bfs(){
queue<int> q; q.push(s);
memset(dep, 0, sizeof(dep)), dep[s] = 1;
while(!q.empty()){
int u = q.front(); q.pop();
for(int i = now[u] = head[u]; ~i; i = e[i].nxt)
if(e[i].w && !dep[e[i].v])
q.push(e[i].v), dep[e[i].v] = dep[u] + 1;
}
return dep[t];
}
ll dfs(int u, ll in){
if(u == t) return in; ll out = 0;
for(int i = now[u]; ~i && in; i = e[i].nxt){
int v = e[i].v; ll w = e[i].w; now[u] = i;
if(dep[v] == dep[u] + 1 && w){
ll flow = dfs(v, min(in, (ll)w));
in -= flow, out += flow;
e[i].w -= flow, e[i ^ 1].w += flow;
}
}
if(!out) dep[u] = 0; return out;
}
ll dinic(){
ll ret = 0;
while(bfs()) ret += dfs(s, INF);
return ret;
}
int main(){
memset(head, -1, sizeof(head));
scanf("%d%d", &n, &m), s = ++tot, t = ++tot;
FL(i, 1, n) FL(j, 1, m){
scanf(" %c", &mp[i][j]), cnt += mp[i][j] == '#';
if(mp[i][j] == '#' && mp[i - 1][j] == '#')
Adde(s, e1[i][j] = ++tot, 1), Adde(e1[i][j], s, 0);
if(mp[i][j] == '#' && mp[i][j - 1] == '#')
Adde(e2[i][j] = ++tot, t, 1), Adde(t, e2[i][j], 0);
}
FL(i, 1, n) FL(j, 1, m){
if(mp[i - 1][j] == '#' && mp[i][j - 1] == '#')
Adde(e1[i][j], e2[i][j], 1), Adde(e2[i][j], e1[i][j], 0);
if(mp[i - 1][j] == '#' && mp[i][j + 1] == '#')
Adde(e1[i][j], e2[i][j + 1], 1), Adde(e2[i][j + 1], e1[i][j], 0);
if(mp[i + 1][j] == '#' && mp[i][j - 1] == '#')
Adde(e1[i + 1][j], e2[i][j], 1), Adde(e2[i][j], e1[i + 1][j], 0);
if(mp[i + 1][j] == '#' && mp[i][j + 1] == '#')
Adde(e1[i + 1][j], e2[i][j + 1], 1), Adde(e2[i][j + 1], e1[i + 1][j], 0);
}
printf("%lld\n", cnt - (tot - 2 - dinic()));
return 0;
}

浙公网安备 33010602011771号