好久没有写博客了。不过这个博客也没有多少人看

最近在写网络流,为了加深理解,来写一两篇题解。

对整个棋盘进行黑白染色以后可以发现,一次操作就是让二分图的两个点的值分别 \(+1\)。

这样,我们就可以对一个答案的合法性做出判断了。

对于每个白点,从 \(S\) 向它连 \(ans - a[i][j]\) 的边。黑点向 \(T\) 连 \(ans - a[i][j]\) 的边。每个白点向黑点建 \(+\infty\) 的边。

如果满流就成立。

发现答案满足单调性,然后就开始非常开心地二分答案?

你会发现从 \(S\) 出来的容量和与流向 \(T\) 的容量和根本不一定等。

但是它们必须等。

于是我们设 \(cnt_1\) 为白点的数量,\(sum_1\) 为白点初始权值之和。\(cnt_0, sum_0\) 为黑点的。

那么必须有:

\[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]奇怪的游戏 最大流的更多相关文章

  1. BZOJ2756:[SCOI2012]奇怪的游戏(最大流,二分)

    Description Blinker最近喜欢上一个奇怪的游戏. 这个游戏在一个 N*M 的棋盘上玩,每个格子有一个数.每次 Blinker 会选择两个相邻 的格子,并使这两个数都加上 1. 现在 B ...

  2. 【BZOJ-2756】奇怪的游戏 最大流 + 分类讨论 + 二分

    2756: [SCOI2012]奇怪的游戏 Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 2925  Solved: 792[Submit][Stat ...

  3. Bzoj2756 [SCOI2012]奇怪的游戏

    2756: [SCOI2012]奇怪的游戏 Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 3220  Solved: 886 Description ...

  4. bzoj2756: [SCOI2012]奇怪的游戏(网络流+分情况)

    2756: [SCOI2012]奇怪的游戏 题目:传送门 题解: 发现做不出来的大难题一点一个网络流 %大佬 首先黑白染色(原来是套路...)染色之后就可以保证每次操作都一定会使黑白各一个各自的值加1 ...

  5. BZOJ 2756: [SCOI2012]奇怪的游戏 [最大流 二分]

    2756: [SCOI2012]奇怪的游戏 Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 3352  Solved: 919[Submit][Stat ...

  6. BZOJ 2756 SCOI2012 奇怪的游戏 最大流

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2756 Description Blinker最近喜欢上一个奇怪的游戏. 这个游戏在一个 N ...

  7. BZOJ2756 [SCOI2012]奇怪的游戏 【网络流 + 二分】

    题目 Blinker最近喜欢上一个奇怪的游戏. 这个游戏在一个 N*M 的棋盘上玩,每个格子有一个数.每次 Blinker 会选择两个相邻 的格子,并使这两个数都加上 1. 现在 Blinker 想知 ...

  8. BZOJ2756 SCOI2012奇怪的游戏(二分答案+最大流)

    由数据范围容易想到网络流.由于操作只是对于棋盘上相邻两格,容易想到给其黑白染色. 假设已经知道最后要变成什么数.那么给黑白点之间连边,其流量则表示同时增加的次数,再用源汇给其限流为需要增加的数即可. ...

  9. BZOJ 2756: [SCOI2012]奇怪的游戏 网络流/二分

    2756: [SCOI2012]奇怪的游戏 Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 1594  Solved: 396[Submit][Stat ...

随机推荐

  1. spring+hibernate单元测试案例

    1,maven创建web工程 2,导入相关依赖 pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmln ...

  2. Jenkins slave-agent.jnlp 无法安装为服务(install as a service)

    问题: 在部署持续集成环境,配置slave节点时遇到一个问题,slave-agent.jnlp可以正常启动运行(不能正常启动的点这里) 但是在保存为系统服务时,slave-agent.jnlp点击[i ...

  3. [CSP-S模拟测试]:数字(数学+高精度)

    题目描述 很简单,给出正整数$n$,求出$n!$在十进制表示下的从最末非零位开始的总共$k$位. 输入格式 第一行一个正整数$T$,表示有$T$组数据接下来$T$行,每行两个正整数$n$和$k$. 输 ...

  4. Myeclipse优化配置

    #utf8 (do not remove)#utf8 (do not remove)-startup../Common/plugins/org.eclipse.equinox.launcher_1.2 ...

  5. Spring cloud gateway自定义filter以及负载均衡

    自定义全局filter package com.example.demo; import java.nio.charset.StandardCharsets; import org.apache.co ...

  6. Vue自定义事件:触发自定义事件

    一 项目结构 二 子组件(Mongo.vue) <template> <button @click="eat">按钮</button> < ...

  7. Mac获取Jenkins管理员初始密码

    前言 最近在配置jenkins环境,但是启动jenkins后,进入jenkins解锁页时,需要自己获取初始密码. 尝试在访达中输入地址搜索,结果无该文件.后来百度上查看多篇文章后,终于获取到了初始密码 ...

  8. [Udemy] Recommender Systems and Deep Learning in Python

    1. Welcome 主要讲四部分内容: non-personized systems popularity: 基于流行度或者最大利益化的推荐. 缺点也明显:你可能在特殊地方有些特殊需求, 或者你本来 ...

  9. Using Tensorflow SavedModel Format to Save and Do Predictions

    We are now trying to deploy our Deep Learning model onto Google Cloud. It is required to use Google ...

  10. 20190825 On Java8 第十三章 函数式编程

    第十三章 函数式编程 函数式编程语言操纵代码片段就像操作数据一样容易. 虽然 Java 不是函数式语言,但 Java 8 Lambda 表达式和方法引用 (Method References) 允许你 ...