BZOJ2756 [SCOI2012]奇怪的遊戲 最大流
阿新 • • 發佈:2019-04-13
n) || play fec long long 但是 遊戲 沒有 printf 為白點的數量,\(sum_1\) 為白點初始權值之和。\(cnt_0, sum_0\) 為黑點的。
好久沒有寫博客了。不過這個博客也沒有多少人看
最近在寫網絡流,為了加深理解,來寫一兩篇題解。
對整個棋盤進行黑白染色以後可以發現,一次操作就是讓二分圖的兩個點的值分別 \(+1\)。
這樣,我們就可以對一個答案的合法性做出判斷了。
對於每個白點,從 \(S\) 向它連 \(ans - a[i][j]\) 的邊。黑點向 \(T\) 連 \(ans - a[i][j]\) 的邊。每個白點向黑點建 \(+\infty\) 的邊。
如果滿流就成立。
發現答案滿足單調性,然後就開始非常開心地二分答案?
你會發現從 \(S\) 出來的容量和與流向 \(T\) 的容量和根本不一定等。
但是它們必須等。
於是我們設 \(cnt_1\)
那麽必須有:
\[
ans \cdot cnt_0 - sum_0 = ans \cdot cnt_1 - sum_1
\]
可以化成
\[
(cnt_o - cnt_1) \cdot ans = sum_0 - sum_1
\]
如果 \(cnt_0 \neq cnt_1\) 可以直接把 \(ans\) 算出來驗證一下就可以了。
如果 \(cnt_o = cnt_1\) 那麽就是說 \(sum_o = sum_1\) 不滿足就可以直接 Skipped
了。如果滿足的話 \(ans\) 可以隨便取值,那麽就可以二分求出最小的了。
#include<bits/stdc++.h> #define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to) #define dbg(...) fprintf(stderr, __VA_ARGS__) #define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout) #define fi first #define se second #define pb push_back template<typename A, typename B> inline char SMAX(A &a, const B &b) {return a < b ? a = b , 1 : 0;} template<typename A, typename B> inline char SMIN(A &a, const B &b) {return b < a ? a = b , 1 : 0;} typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii; template<typename I> inline void read(I &x) { int f = 0, c; while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0; x = c & 15; while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15); f ? x = -x : 0; } const int MAXN = 40 + 7; const int N = MAXN * MAXN; const int M = MAXN * MAXN * 3; const int dx[] = {0, 1, 0, -1}; const int dy[] = {1, 0, -1, 0}; const ll INF = 0x3f3f3f3f3f3f3f3f; const int INF_int = 0x3f3f3f3f; int n, m, S, T, nod, cnt0, cnt1, hd, tl, allsize; ll sum0, sum1, sum; int a[MAXN][MAXN], id[MAXN][MAXN], col[MAXN][MAXN]; int q[N], cur[N], dis[N]; struct Edge {int to, ne; ll f;} g[M << 1]; int head[N], tot = 1; inline void addedge(int x, int y, ll z) {g[++tot].to = y; g[tot].f = z; g[tot].ne = head[x]; head[x] = tot;} inline void adde(int x, int y, ll z) {addedge(x, y, z); addedge(y, x, 0);} inline bool bfs() { memset(dis, 0x3f, allsize); memcpy(cur, head, allsize); q[hd = 0, tl = 1] = S; dis[S] = 0; while (hd < tl) { int x = q[++hd]; for fec(i, x, y) if (g[i].f && dis[y] == INF_int) { dis[y] = dis[x] + 1; q[++tl] = y; // dbg("y = %d, T = %d\n", y, T); if (y == T) return 1; } } return 0; } inline ll dfs(int x, ll a) { // dbg("x = %d a = %lld\n", x, a); if (x == T || !a) return a; ll flow = 0, f; for (int &i = cur[x]; i; i = g[i].ne) { int y = g[i].to; if (dis[y] != dis[x] + 1) continue; if (!(f = dfs(y, std::min(a, g[i].f)))) continue; g[i].f -= f, g[i ^ 1].f += f; flow += f, a -= f; if (!a) break; } if (!flow) dis[x] = INF_int; return flow; } inline ll dinic() { ll ans = 0; while (bfs()) ans += dfs(S, INF); // dbg("ans = %lld\n", ans); return ans; } inline bool build(ll mid) { memset(head, 0, sizeof(head)); tot = 1; sum = 0; for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) { if (mid < a[i][j]) return 0; if (col[i][j]) { adde(S, id[i][j], mid - a[i][j]); sum += mid - a[i][j]; for (int k = 0; k < 4; ++k) { int px = i + dx[k], py = j + dy[k]; if (px < 1 || px > n || py < 1 || py > m) continue; adde(id[i][j], id[px][py], INF); } } else adde(id[i][j], T, mid - a[i][j]); } return 1; } inline bool check(ll mid) { if (!build(mid)) return 0; return dinic() == sum; } inline void work() { if (cnt0 == cnt1) { if (sum0 != sum1) { puts("-1"); return; } else { ll l = 0, r = INF; while (l < r) { ll mid = (l + r) >> 1; if (check(mid)) r = mid; else l = mid + 1; } // dbg("l = %d\n", l); // for (ll i = l - 10000; i <= l + 10000; ++i) // dbg("When i = %lld, chk = %d\n", i, (int)check(i)); if (l < INF) printf("%lld\n", l * cnt0 - sum0); else puts("-1"); } } else { ll dsum = sum0 - sum1; int dcnt = cnt0 - cnt1; if (((dsum < 0 && dcnt < 0) || (dsum > 0 && dcnt > 0)) && dsum % dcnt == 0) { ll ans = dsum / dcnt; if (check(ans)) printf("%lld\n", ans * cnt0 - sum0); else puts("-1"); } } } inline void cls() { sum0 = sum1 = 0; cnt0 = cnt1 = 0; } inline void init() { cls(); read(n), read(m); for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { read(a[i][j]); col[i][j] = (i + j) & 1; if (col[i][j]) ++cnt1, sum1 += a[i][j]; else ++cnt0, sum0 += a[i][j]; if (j > 1) id[i][j] = id[i][j - 1] + 1; else id[i][j] = id[i - 1][m] + 1; } } S = id[n][m] + 1, T = nod = id[n][m] + 2; allsize = (nod + 1) * sizeof(int); } int main() { #ifdef hzhkk freopen("hkk.in", "r", stdin); #endif int T; read(T); while (T--) { init(); work(); } fclose(stdin); }
BZOJ2756 [SCOI2012]奇怪的遊戲 最大流