洛谷P2774_方格取數問題_最大流_最小割
阿新 • • 發佈:2019-01-23
題目大意
m * n 的矩陣中取數,不能取相鄰的數,求能取得的數的和最大為多少。
思路
(i, j) 為 i 行 j 列的單元格,根據 i + j 的奇偶性將節點分為兩個集合,在矩陣中相鄰得節點分別在圖的兩側,得一個二分圖。
s 點向左側節點建邊,容量為節點在矩陣中的值。
右側節點向t 建邊,容量為節點在矩陣中的值。
左側節點向在矩陣中相鄰的右側節點建立容量為INF的邊。
進入S集的右側節點不取,進入T集的左側節點不取,所得的最小割的值即為不取的數的和。
ans = sum - max_flow
左側節點a和右側節點b,如果在矩陣中相鄰,則必須同時進入S集或T集,也就是說,a和b不能同時取得(如果同時進入S集則取a不取b)。因此建圖時,a和b之間的邊容量為INF,INF的邊不能進入割集。
選擇a和b進入S集或T集的過程是同過 比較a和b的權值 決策取捨a和b的過程。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <vector> #include <queue> #define INF 0x3f3f3f3f #define rep0(i, n) for (int i = 0; i < n; i++) #define rep1(i, n) for (int i = 1; i <= n; i++) #define rep_0(i, n) for (int i = n - 1; i >= 0; i--) #define rep_1(i, n) for (int i = n; i > 0; i--) #define MAX(x, y) (((x) > (y)) ? (x) : (y)) #define MIN(x, y) (((x) < (y)) ? (x) : (y)) #define mem(x, y) memset(x, y, sizeof(x)) #define MAXN 110 using namespace std; typedef long long ll; const int S = 0, T = MAXN * MAXN - 1; struct Edge { int to, cap, flow, rev; }; vector<Edge> g[MAXN * MAXN]; int grid[MAXN][MAXN], m, n; int idx(int i, int j) { return i * n + j + 1; } void addEdge(int u, int v, int cap) { g[u].push_back((Edge){v, cap, 0, g[v].size()}); g[v].push_back((Edge){u, 0, 0, g[u].size() - 1}); } int level[MAXN * MAXN], itr[MAXN * MAXN]; queue<int> q; void bfs() { mem(level, -1); q.push(S); level[S] = 0; while (!q.empty()) { int u = q.front(); q.pop(); for (int i = 0; i < g[u].size(); i++) { Edge e = g[u][i]; if (level[e.to] < 0 && e.cap > e.flow) { level[e.to] = level[u] + 1; q.push(e.to); } } } } int dfs(int u, int f) { if (u == T) return f; for (int& i = itr[u]; i < g[u].size(); i++) { Edge& e = g[u][i]; if (level[e.to] > level[u] && e.cap > e.flow) { int d = dfs(e.to, MIN(f, e.cap - e.flow)); if (d) { e.flow += d; g[e.to][e.rev].flow -= d; return d; } } } return 0; } ll max_flow() { ll flow = 0; while (true) { bfs(); if (level[T] < 0) return flow; ll f; mem(itr, 0); while ((f = dfs(S, INF)) > 0) { flow += f; } } } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif // ONLINE_JUDGE ll ans = 0; scanf("%d %d", &m, &n); for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) { scanf("%d", &grid[i][j]); ans += grid[i][j]; } for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if ((i + j) & 1) { addEdge(idx(i, j), T, grid[i][j]); if (i - 1 >= 0) addEdge(idx(i - 1, j), idx(i, j), INF); if (j - 1 >= 0) addEdge(idx(i, j - 1), idx(i, j), INF); } else { addEdge(S, idx(i, j), grid[i][j]); if (i - 1 >= 0) addEdge(idx(i, j), idx(i - 1, j), INF); if (j - 1 >= 0) addEdge(idx(i, j), idx(i, j - 1), INF); } } } ans -= max_flow(); printf("%lld\n", ans); return 0; }