[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=1475
[算法]
首先将方格黑白染色 , 也就是说 , 如果(i + j)为奇数 , 这个点就是黑点 , 否则是白点
那么这个n * n的方格就被分为了两个集合 , 一个是黑点集合 , 一个是白点集合
如果选取一个黑点 , 造成影响的是四方向内的白点
如果选取一个白点 , 造成影响的是四方向内的黑点
考虑首先选取所有的点 , 然后去掉最小代价的点 , 并使方案合法
那么这就是一个最小割的经典模型 :
将源点向所有黑点连流量为权值的边
将所有白点向汇点连流量为权值的边
将所有黑点向四方向内的白点连流量为正无穷的边
求解这个图的最小割即可
时间复杂度 : O(dinic(N , M))
[代码]
#include<bits/stdc++.h> using namespace std; #define N 110 typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int inf = 1e9; const int dx[4] = {0 , 0 , -1 , 1}; const int dy[4] = {-1 , 1 , 0 , 0}; struct edge { int to , w , nxt; } e[N * N * 2]; int n , m , S , T , tot; int a[N][N]; int dep[N * N] , head[N * N]; template <typename T> inline void chkmin(T &x , T y) { x = min(x , y); } template <typename T> inline void chkmax(T &x , T y) { x = max(x , y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } inline bool bfs(int s) { queue< int > q; q.push(s); memset(dep , 255 , sizeof(dep)); dep[s] = 1; while (!q.empty()) { int cur = q.front(); q.pop(); for (int i = head[cur]; i; i = e[i].nxt) { int v = e[i].to , w = e[i].w; if (w > 0 && dep[v] == -1) { dep[v] = dep[cur] + 1; q.push(v); if (v == T) return true; } } } return false; } inline int dinic(int u , int flow) { int rest = flow; if (u == T) return flow; for (int i = head[u]; i && rest; i = e[i].nxt) { int v = e[i].to , w = e[i].w; if (dep[v] == dep[u] + 1 && w > 0) { int k = dinic(v , min(w , rest)); if (!k) dep[v] = 0; rest -= k; e[i].w -= k; e[i ^ 1].w += k; } } return flow - rest; } inline void addedge(int u , int v , int w) { ++tot; e[tot] = (edge){v , w , head[u]}; head[u] = tot; ++tot; e[tot] = (edge){u , 0 , head[v]}; head[v] = tot; } inline bool valid(int x , int y) { return x >= 1 && x <= m && y >= 1 && y <= n; } int main() { read(m); n = m; int cnt = 0; for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { read(a[i][j]); cnt += a[i][j]; } } S = n * m + 1 , T = S + 1; tot = 1; for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { if ((i + j) & 1) addedge(S , (i - 1) * n + j , a[i][j]); else addedge((i - 1) * n + j , T , a[i][j]); } } for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { for (int k = 0; k < 4; k++) { int x = i + dx[k] , y = j + dy[k]; if (valid(x , y) && (i + j) & 1) addedge((i - 1) * n + j , (x - 1) * n + y , inf); } } } int ans = 0; while (bfs(S)) { while (int flow = dinic(S , inf)) ans += flow; } printf("%d\n" , cnt - ans); return 0; }