题解:P12793 [NERC 2022] Dominoes
好题啊
首先对网格图进行黑白染色,这样的话选两个黑或两个白去掉一定不合法,因为答案要对
先考虑暴力怎么做,就是暴力枚举去掉的白点和黑点,然后跑二分图匹配,这样肯定行不通。
再进行一些观察,不难发现因为原图合法,所以考虑先对原图找出一组合法的二分图匹配。接下来如果要去掉一对点,那么要求去掉后的匹配数只减掉
每次从一个起点遍历增广路即可,设点数为
const int N = 2e3 + 5;
const int M = 1e5 + 5;
const int V = 1e6;
const int INF = 0x3f3f3f3f;
int n, m;
string s[N];
int a[N][N], cnt;
int dx[] = {0, 0, 1, - 1};
int dy[] = {1, - 1, 0, 0};
struct Edge { int ne, to, ew; } e[M];
int fi[N], c[N], ecnt;
int S, T, d[N];
int vis[N];
void init() {
ecnt = 1;
memset(fi, 0, sizeof fi);
}
void add(int u, int v, int w) {
e[++ ecnt] = {fi[u], v, w};
fi[u] = ecnt;
e[++ ecnt] = {fi[v], u, 0};
fi[v] = ecnt;
}
bool bfs() {
memset(d, 0x3f, sizeof d);
queue<int> q;
d[S] = 0; q.push(S);
while(! q.empty()) {
int u = q.front();
q.pop();
for(int i = fi[u]; i; i = e[i].ne) if(e[i].ew) {
int v = e[i].to;
if(d[v] == INF) {
d[v] = d[u] + 1;
q.push(v);
}
}
}
return d[T] != INF;
}
int dfs(int u, int w) {
if(u == T || ! w) return w;
int res = 0;
for(int & i = c[u]; i; i = e[i].ne) if(e[i].ew) {
int v = e[i].to;
if(d[v] != d[u] + 1) continue;
int val = dfs(v, min(w, e[i].ew));
if(! val) continue;
e[i].ew -= val;
e[i ^ 1].ew += val;
w -= val;
res += val;
if(! w) return res;
}
return res;
}
int dinic(int _S, int _T) {
S = _S, T = _T;
int res = 0;
while(bfs()) {
memcpy(c, fi, sizeof c);
res += dfs(S, INF);
}
return res;
}
void solve() {
cin >> n >> m;
FOR(i, 1, n) {
cin >> s[i];
s[i] = ' ' + s[i];
}
FOR(i, 1, n) FOR(j, 1, m) if(s[i][j] == '.') if((i + j) & 1)
a[i][j] = ++ cnt;
FOR(i, 1, n) FOR(j, 1, m) if(s[i][j] == '.') if(! ((i + j) & 1))
a[i][j] = ++ cnt;
cnt /= 2;
if(1ll * cnt * (cnt - 1) >= V) {
cout << V << endl;
return;
}
int S = 0, T = cnt * 2 + 1;
init();
FOR(i, 1, cnt) add(S, i, 1);
FOR(i, 1, cnt) add(i + cnt, T, 1);
FOR(i, 1, n) FOR(j, 1, m) if(s[i][j] == '.') if((i + j) & 1) REP(d, 4) {
int x = i + dx[d], y = j + dy[d];
if(x < 1 || x > n || y < 1 || y > m) continue;
if(s[x][y] == '#') continue;
add(a[i][j], a[x][y], 1);
}
dinic(S, T);
int ans = cnt * (cnt - 1);
FOR(i, 1, cnt) {
FOR(j, 1, cnt * 2) vis[j] = 0;
queue<int> q;
q.push(i); vis[i] = 1;
while(! q.empty()) {
int u = q.front();
q.pop();
for(int i = fi[u]; i; i = e[i].ne) if(e[i ^ 1].ew) {
int v = e[i].to;
if(v == S || v == T) continue;
if(! vis[v]) {
vis[v] = 1;
q.push(v);
}
}
}
FOR(j, cnt + 1, cnt * 2) ans += ! vis[j];
}
chmin(ans, V);
cout << ans << endl;
}