Maze 第二十届浙大城市学院程序设计竞赛 (二分图,网络流(对于表格,矩阵是如何建边的))
题目大意:
- 给出一个01矩阵, 给出q,p 分别表示 选一个点的权值,和选2个连在一起的点的权值
- 问如何让权值更大
注意 : 在Dinic 的时间复杂度对于二分图这种边权为1, 时间复杂度为 NsqrtN, 不是n^2 m
思路:
- 更具题目的条件限制,他的建边一定是2个矮在一起的
- 因此更具 (i+j)%2, 连转换成二分图, (在一边的2个点一定不会建边)
- 然后网络流Dinic跑二分图匹配即可
#include <bits/stdc++.h> using namespace std; const int N = 310; const int V = N * N, E = V << 2; template <class T> struct FlowGraph { int s, t, totv, idx, head[V], dis[V], cur[V]; struct edge { int v, nxt; T f; } e[E << 1]; void addedge(int u, int v, T f) { //有向边反边权值为0,无向边为f e[idx] = {v, head[u], f}; head[u] = idx++; e[idx] = {u, head[v], 0}; head[v] = idx++; } int bfs() { for (int i = 1; i <= totv; i++) { dis[i] = 0; cur[i] = head[i]; } dis[s] = 1; queue<int> q; q.push(s); while (q.size()) { int sz = q.size(); while (sz--) { int u = q.front(); q.pop(); for (int i = head[u]; ~i; i = e[i].nxt) { if (e[i].f && !dis[e[i].v]) { int v = e[i].v; dis[v] = dis[u] + 1; if (v == t) return 1; q.push(v); } } } } return 0; } T dfs(int u, T rem) { if (u == t) return rem; T flow = 0; for (int i = cur[u]; ~i; cur[u] = i = e[i].nxt) { if (e[i].f && dis[e[i].v] == dis[u] + 1) { int v = e[i].v; T f = dfs(v, min(rem, e[i].f)); e[i].f -= f; e[i ^ 1].f += f; rem -= f; flow += f; if (!rem) break; } } if (!flow) dis[u] = -1; return flow; } T dinic() { T flow = 0; while (bfs()) flow += dfs(s, 0x3f3f3f3f); return flow; } void init(int _s, int _t, int _totv) { s = _s; t = _t; totv = _totv; idx = 0; for (int i = 1; i <= totv; i++) head[i] = -1; } }; FlowGraph<int> g; int n, m, p, q, vis[N][N], id[N][N], col[N * N]; char s[N][N]; long long ans; pair<int, int> path[E]; void solve(int sx, int sy) { int cnt = 0, idx = 0; auto get = [&](int x, int y) { if (id[x][y] == 0) { id[x][y] = ++idx; col[idx] = (x + y) & 1; } return id[x][y]; }; get(sx, sy); auto add = [&](int x, int y) { if (col[x] == 0) g.addedge(x, y, 1); }; function <void(int, int)> dfs = [&](int x, int y) { vis[x][y] = 1; if (x + 1 <= n && s[x + 1][y] == '1') { if (!vis[x + 1][y]) dfs(x + 1, y); path[++cnt] = {get(x, y), get(x + 1, y)}; } if (y + 1 <= m && s[x][y + 1] == '1') { if (!vis[x][y + 1]) dfs(x, y + 1); path[++cnt] = {get(x, y), get(x, y + 1)}; } if (y - 1 >= 1 && s[x][y - 1] == '1') { if (!vis[x][y - 1]) dfs(x, y - 1); path[++cnt] = {get(x, y), get(x, y - 1)}; } if (x - 1 >= 1 && s[x - 1][y] == '1') { if (!vis[x - 1][y]) dfs(x - 1, y); path[++cnt] = {get(x, y), get(x - 1, y)}; } }; dfs(sx, sy); int S = idx + 1, T = idx + 2; g.init(S, T, T);; for (int i = 1; i <= cnt; i++) add(path[i].first, path[i].second); for (int i = 1; i <= idx; i++) { if (col[i] == 0) { g.addedge(S, i, 1); } else { g.addedge(i, T, 1); } } int maxV = g.dinic(); ans += max(1ll * maxV * q + 1ll * (idx - maxV * 2) * p, 1ll * idx * p); } int main() { ios::sync_with_stdio(0); cin.tie(0); cin >> n >> m >> p >> q; for (int i = 1; i <= n; i++) { cin >> (s[i] + 1); } for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { if (!vis[i][j] && s[i][j] == '1') { solve(i, j); } } } cout << ans; return 0; }