旺崽的博客

要么天赋异禀,要么天道酬勤

0%

Caddi Programming Contest 2021(AtCoder Beginner Contest 193) F.Zebraness

题目链接

Problem Statement

We have a grid with N horizontal rows and N vertical columns.
Let (i,j) denote the square at the i-th row from the top and j-th column from the left. A character $c_{i,j}$ describes the color of (i,j).
B means the square is painted black; W means the square is painted white; ? means the square is not yet painted.

Takahashi will complete the black-and-white grid by painting each unpainted square black or white.
Let the zebraness of the grid be the number of pairs of a black square and a white square sharing a side.
Find the maximum possible zebraness of the grid that Takahashi can achieve.

Sample Input 1

1
2
3
2
BB
BW

Sample Output 1

1
2

Sample Input 2

1
2
3
4
3
BBB
BBB
W?W

Sample Output 2

1
4

Sample Input 3

1
2
3
4
5
6
5
?????
?????
?????
?????
?????

Sample Output 3

1
40

建图+网络流~
对一个为 n*n 的矩阵,显然最大值就是 2n(n-1),那么这题就可以转化成一个最小割(或者最大流),答案就是最大值减去最小割,建图如下:

  • 每一个点和四周的点连边,流量为 $1$
  • 对所有非 ? 的点,判断奇偶性连一条 inf 边到源点或者汇点

注意算法复杂度,EK 算法可能会超时,要用 Dicnic 算法,AC代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 5;
#define inf 0x3f3f3f3f

struct edge {
int from, to;
int cap;
int flow;

edge(int u, int v, int c, int f) : from(u), to(v), cap(c), flow(f) {
}
};

vector<edge> edges;
vector<int> G[MAXN];
int vis[MAXN];
int d[MAXN];
int cur[MAXN];
int m;
int s, t;

void add(int from, int to, int cap) {
edges.push_back(edge(from, to, cap, 0));
edges.push_back(edge(to, from, 0, 0));
int m = edges.size();
G[from].push_back(m - 2);
G[to].push_back(m - 1);
}

bool bfs() {
memset(vis, 0, sizeof(vis));
queue<int> q;
q.push(s);
d[s] = 1;
vis[s] = 1;
while (!q.empty()) {
int x = q.front();
q.pop();
for (int i = 0; i < G[x].size(); i++) {
edge &e = edges[G[x][i]];
if (!vis[e.to] && e.cap > e.flow) {
vis[e.to] = 1;
d[e.to] = d[x] + 1;
q.push(e.to);
}
}

}
return vis[t];
}

int dfs(int x, int a) {
if (x == t || a == 0)
return a;
int flow = 0, f;
for (int &i = cur[x]; i < G[x].size(); i++) {
edge &e = edges[G[x][i]];
if (d[x] + 1 == d[e.to] && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0) {
e.flow += f;
edges[G[x][i] ^ 1].flow -= f;
flow += f;
a -= f;
if (a == 0)
break;
}
}
return flow;
}

int dicnic() {
int ans = 0;
while (bfs()) {
memset(cur, 0, sizeof(cur));
ans += dfs(s, inf);
}
return ans;
}

int main() {
int n;
cin >> n;
vector<string> c(n);
for (int i = 0; i < n; i++) cin >> c[i];
s = n * n + 1, t = n * n + 2;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
int x = i * n + j;
if (c[i][j] == 'B') {
if ((i + j) % 2) add(s, x, inf);
else add(x, t, inf);
} else if (c[i][j] == 'W') {
if ((i + j) % 2) add(x, t, inf);
else add(s, x, 10);
}
if (i < n - 1) {
int y = (i + 1) * n + j;
add(x, y, 1);
add(y, x, 1);
}
if (j < n - 1) {
int y = i * n + j + 1;
add(x, y, 1);
add(y, x, 1);
}
}
}
cout << 2 * n * (n - 1) - dicnic();
return 0;
}