题目大意:给你一个$n imes m$的方格,要求你从中选择一些数,其中没有相邻两个数,使得最后和最大
题解:网络流,最小割,发现相邻的两个点不可以同时选择,进行黑白染色,原点向黑点连一条容量为点权的边,白点向汇点连一条容量为点权的边,黑点向周围一圈的白点连容量为$inf$的边,总权值减去跑出来的最小割就是答案。
卡点:无
C++ Code:
#include <algorithm> #include <cstdio> #include <cctype> namespace __IO { namespace R { int x, ch; inline int read() { ch = getchar(); while (isspace(ch)) ch = getchar(); for (x = ch & 15, ch = getchar(); isdigit(ch); ch = getchar()) x = x * 10 + (ch & 15); return x; } } } using __IO::R::read; #define maxn 100010 #define maxm (maxn << 3) const int inf = 0x3f3f3f3f; int n, m, sum; namespace Network_Flow { int st, ed, MF; int head[maxn], cnt = 1; struct Edge { int to, nxt, w; } e[maxm << 1]; inline void addedge(int a, int b, int c) { e[++cnt] = (Edge) {b, head[a], c}; head[a] = cnt; e[++cnt] = (Edge) {a, head[b], 0}; head[b] = cnt; } int GAP[maxn], d[maxn], lst[maxn]; int q[maxn], h, t; void init() { GAP[d[ed] = 1] = 1; for (int i = st; i <= ed; i++) lst[i] = head[i]; q[h = t = 0] = ed; while (h <= t) { int u = q[h++]; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (!d[v]) { d[v] = d[u] + 1; GAP[d[v]]++; q[++t] = v; } } } } int dfs(int u, int low) { if (!low || u == ed) return low; int w, res = 0; for (int &i = lst[u]; i; i = e[i].nxt) if (e[i].w) { int v = e[i].to; if (d[u] == d[v] + 1) { w = dfs(v, std::min(low, e[i].w)); res += w, low -= w; e[i].w -= w, e[i ^ 1].w += w; if (!low) return res; } } if (!(--GAP[d[u]])) d[st] = ed + 1; ++GAP[++d[u]], lst[u] = head[u]; return res; } void ISAP(int __st, int __ed) { st = __st, ed = __ed; init(); while (d[st] <= ed) MF += dfs(st, inf); } } using Network_Flow::addedge; inline int get(int x, int y) {return (x - 1) * m + y;} const int D[2][4] = {{0, 1, 0, -1}, {1, 0, -1, 0}}; inline bool over_range(int x, int y) { return x < 1 || x > n || y < 1 || y > m; } int main() { n = read(), m = read(); int st = 0, ed = n * m + 1; for (int i = 1, x, pos; i <= n; i++) { for (int j = 1; j <= m; j++) { sum += x = read(), pos = get(i, j); if (i + j & 1) { addedge(st, pos, x); for (int k = 0; k < 4; k++) { int __x = i + D[0][k], __y = j + D[1][k]; if (!over_range(__x, __y)) addedge(pos, get(__x, __y), inf); } } else addedge(pos, ed, x); } } Network_Flow::ISAP(st, ed); printf("%d ", sum - Network_Flow::MF); return 0; }