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
113
114
115
116
117
118
119
120
121
122
123
|
#include <cassert>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#define mkp make_pair
#define fi first
#define se second
using namespace std;
const int _ = 2e4 + 7;
const int __ = 1e5 + 7;
const int inf = 1;
const int S = 2e4 + 1, T = 2e4 + 2;
int n, m, nm, All[2], MaxFlow, Cst;
int dis[_], dep[_], lst[_], cur[_], nxt[__], to[__], cap[__], wgt[__], tot = 1;
bool b[_];
queue<int> q;
int Num(int i, int j) {
if (i < 1 or i > n or j < 1 or j > m) return 0;
return m * (i - 1) + j;
}
int pop_count(int x) { return (x & 1) + (x >> 1 & 1) + (x >> 2 & 1) + (x >> 3 & 1); }
void Add(int x, int y, int c, int w, bool ty = 1) {
if (!x or !y) return;
if (!ty) swap(x, y);
nxt[++tot] = lst[x], to[tot] = y, cap[tot] = c, wgt[tot] = w, lst[x] = tot;
nxt[++tot] = lst[y], to[tot] = x, cap[tot] = 0, wgt[tot] = -w, lst[y] = tot;
}
bool SPFA() {
memset(dis, 0x3f, sizeof dis), memset(dep, 0, sizeof dep);
dis[S] = 0, dep[S] = 1, q.push(S);
while (!q.empty()) {
int u = q.front(); q.pop(), b[u] = 0;
for (int i = lst[u]; i; i = nxt[i]) {
int v = to[i];
if (dis[v] <= dis[u] + wgt[i] or !cap[i]) continue;
dis[v] = dis[u] + wgt[i], dep[v] = dep[u] + 1;
if (!b[v]) q.push(v), b[v] = 1;
}
}
return dis[T] != dis[0];
}
int Extend(int u, int flow) {
if (u == T) return flow;
int res = flow;
for (int &i = cur[u]; i; i = nxt[i]) {
int v = to[i];
if (dis[v] != dis[u] + wgt[i] or dep[v] != dep[u] + 1 or !cap[i]) continue;
int cst = Extend(v, min(res, cap[i]));
cap[i] -= cst, cap[i ^ 1] += cst, res -= cst;
if (!res) break;
}
return flow - res;
}
void Dinic() {
int flow;
while (SPFA()) {
memcpy(cur, lst, sizeof lst);
do {
flow = Extend(S, inf);
MaxFlow += flow;
Cst += flow * dis[T];
} while (flow);
}
}
int main() {
cin >> n >> m; nm = n * m;
for (int i = 1, x, id, cnt, ty; i <= n; ++i)
for (int j = 1; j <= m; ++j) {
scanf("%d", &x), cnt = pop_count(x), id = Num(i, j), ty = (i + j) & 1;
if (!cnt) continue;
All[ty] += cnt;
if (ty) Add(S, id, cnt, 0);
else Add(id, T, cnt, 0);
for (int k = 0; k < 4; ++k)
if (x >> k & 1) Add(id, (k + 1) * nm + id, 1, 0, ty);
bool flag = cnt == 2 and (((x >> 0 & 1) and (x >> 2 & 1)) or ((x >> 1 & 1) and (x >> 3 & 1)));
if (cnt == 1) {
int t = 0;
for (int k = 0; k < 4; ++k)
if (x >> k & 1) t = k;
for (int k = 0; k < 4; ++k)
if ((k - t + 4) % 4 == 2) Add(id, (k + 1) * nm + id, 1, 2, ty);
else if (k != t) Add(id, (k + 1) * nm + id, 1, 1, ty);
}
if (cnt == 2 and !flag) {
for (int k = 0; k < 4; ++k)
if (x >> k & 1) Add((k + 1) * nm + id, ((k + 2) % 4 + 1) * nm + id, 1, 1, ty);
}
else if (cnt == 3) {
int t = 0;
for (int k = 0; k < 4; ++k)
if (!(x >> k & 1)) t = k;
Add(((t + 2) % 4 + 1) * nm + id, (t + 1) * nm + id, 1, 2, ty);
Add(((t + 1) % 4 + 1) * nm + id, (t + 1) * nm + id, 1, 1, ty);
Add(((t + 3) % 4 + 1) * nm + id, (t + 1) * nm + id, 1, 1, ty);
}
if (ty) {
int n1 = Num(i - 1, j), n2 = Num(i, j + 1), n3 = Num(i + 1, j), n4 = Num(i, j - 1);
if (n1) Add(1 * nm + id, 3 * nm + n1, 1, 0);
if (n2) Add(2 * nm + id, 4 * nm + n2, 1, 0);
if (n3) Add(3 * nm + id, 1 * nm + n3, 1, 0);
if (n4) Add(4 * nm + id, 2 * nm + n4, 1, 0);
}
}
if (All[0] != All[1]) { puts("-1"); exit(0); }
Dinic();
printf("%d\n", MaxFlow == All[0] ? Cst : -1);
return 0;
}
|