[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;
}
posted @ 2021-03-02 16:28  evenbao  阅读(156)  评论(0编辑  收藏  举报