Forever Young

网络流24题 P2774 方格取数问题

思路

问题模型:二分图点权最大独立集

转化模型:网络最小割

不想说太多废话了,所以这是一篇精简的题解 \(\texttt{qwq}\)

因为相邻的点只能选一个,所以考虑把图分成两部分,相邻的两个点一定不在同一边,由此变成二分图

然后找出最小割,用所有的和减去最小割就是答案,又因为最大流=最小割,所以算出最大流即可

代码

/*
  Name: 方格取数问题 
  Author: Loceaner
  Date: 24/08/20 21:16
*/
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define id (m * (i - 1) + j)
using namespace std;

const int A = 1e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

inline int read() {
  char c = getchar();
  int x = 0, f = 1;
  for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
  for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
  return x * f;
}

int dx[5] = { 0, 1, 0, -1, 0 };
int dy[5] = { 0, 0, 1, 0, -1 };
int n, m, s, t, cnt = 1, sum, ans;
struct node { int to, nxt, val; } e[A];
int head[A], dep[A], inq[A], cur[A], r[A], c[A], a[100][100];

inline void add(int from, int to, int val) {
  e[++cnt].to = to;
  e[cnt].val = val;
  e[cnt].nxt = head[from];
  head[from] = cnt;
}

inline bool bfs() {
  queue <int> Q;
  for (int i = 1; i <= n * m + 2; i++) 
    cur[i] = head[i], inq[i] = 0, dep[i] = inf;
  dep[s] = 0, Q.push(s), inq[s] = 1;
  while (!Q.empty()) {
    int x = Q.front(); Q.pop(), inq[x] = 0;
    for (int i = head[x]; i; i = e[i].nxt) {
      int to = e[i].to;
      if (dep[to] > dep[x] + 1 && e[i].val) {
        dep[to] = dep[x] + 1;
        if (!inq[to]) Q.push(to), inq[to] = 1;
      }
    }
  }
  return dep[t] != inf;
}

int dfs(int x, int flow) {
  if (x == t) return flow;
  int tmp = 0;
  for (int i = cur[x]; i; i = e[i].nxt) {
    cur[x] = i;
    int to = e[i].to;
    if (dep[to] == dep[x] + 1 && e[i].val) {
      if (tmp = dfs(to, min(flow, e[i].val))) {
        e[i].val -= tmp, e[i ^ 1].val += tmp;
        return tmp;
      }
    }
  }
  return 0;
}

int main() {
  n = read(), m = read();
  s = n * m + 1, t = n * m + 2;
  for (int i = 1; i <= n; i++)
    for (int j = 1; j <= m; j++) 
      a[i][j] = read(), sum += a[i][j];
  for (int i = 1; i <= n; i++) 
    for (int j = 1; j <= m; j++) {
      if (!((i + j) % 2)) add(s, id, a[i][j]), add(id, s, 0);
      else add(id, t, a[i][j]), add(t, id, 0);
      for (int h = 1; h <= 4; h++) {
        int lx = i + dx[h], ly = j + dy[h];
        if (lx >= 1 && lx <= n && ly >= 1 && ly <= m)
          if ((lx + ly) % 2) 
            add(id, (lx - 1) * m + ly, inf), add((lx - 1) * m + ly, id, 0);
      }
    }
  int ans = 0, now = 0;
  while (bfs()) while (now = dfs(s, inf)) ans += now;
  cout << sum - ans << '\n';
  return 0;
}
posted @ 2020-08-24 21:41  Loceaner  阅读(95)  评论(0编辑  收藏  举报