[CF1404E] Bricks
[题目链接]
http://codeforces.com/contest/1404/problem/E
[题解]
首先将每个 \(1 * 2\) 和 \(2 * 1\) 的格子编号。
对于每个位置相当于限制了不能有一个 \(1 * 2\) 和 \(2 * 1\) 相交于此点。将其连边。
于是只需求二分图最大独立集即可。
二分图最大独立集 = 点数 - 最大匹配。
时间复杂度 : \(O(N ^ 3)\)
[代码]
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i , l , r) for (int i = (l); i < (r); ++i)
const int MN = 205;
int N , M , cnt = 0 , tot = 0 , le = 0 , ri = 0 , mat[MN * MN] , chk[MN * MN];
char s[MN][MN];
vector < int > adj[MN * MN] , hor[MN][MN] , ver[MN][MN];
inline bool DFS(int u) {
chk[u] = tot + 1;
for (int v : adj[u])
if (mat[v] == 0) {
mat[v] = u;
return true;
}
for (int v : adj[u])
if (chk[mat[v]] <= tot && DFS(mat[v])) {
mat[v] = u;
return true;
}
return false;
}
int main() {
scanf("%d%d" , &N , &M);
for (int i = 1; i <= N; ++i) {
scanf("%s" , s[i] + 1);
for (int j = 1; j <= M; ++j)
cnt += (s[i][j] == '#');
}
for (int i = 1; i <= N; ++i)
for (int j = 1; j < M; ++j)
if (s[i][j] == '#' && s[i][j + 1] == '#') {
++le;
hor[i][j].emplace_back(le);
hor[i][j + 1].emplace_back(le);
}
for (int i = 1; i < N; ++i)
for (int j = 1; j <= M; ++j)
if (s[i][j] == '#' && s[i + 1][j] == '#') {
++ri;
ver[i][j].emplace_back(ri);
ver[i + 1][j].emplace_back(ri);
}
for (int i = 1; i <= N; ++i)
for (int j = 1; j <= M; ++j)
for (int u : hor[i][j])
for (int v : ver[i][j])
adj[u].emplace_back(v);
for (int i = 1; i <= le; ++i)
tot += DFS(i);
printf("%d\n" , cnt - (le + ri - tot));
return 0;
}