费用流。
把每个方格拆成 $T$ 个点,$t$ 时刻一个方格向周围四个方格的 $t + 1$ 的点连一条容量为 $1$ 费用为 $0$ 的边,向自身的 $t + 1$ 连一条容量为 $1$ 费用为该方格最大幸福值的边。
源点向方格为 'S' 的0时刻连一条容量为 $1$ 费用为 $0$ 的边。所有点的 $T - 1$ 时刻向汇点连一条容量为 $1$ 费用为该方格最大幸福值的边。
还有每个格子同时刻不能有多条蛇呆在上面,再把每个点每个时刻拆成两个点,容量为 $1$ 费用为 $0$。跑最大费用最大流即可。
#include <bits/stdc++.h> using namespace std; const int N = 300; const int NN = 1e5 + 7, M = 5e5 + 7; const int INF = 0x3f3f3f3f; template<class T> inline void checkmax(T &a, T b) { if (a < b) a = b; } template<class T> inline void checkmin(T &a, T b) { if (a > b) a = b; } struct E { int v, ne, f, c; } e[M]; int head[NN], cnt, tol; int id[N][N][85], mp[N][N][85]; int dis[NN], path[NN], n, m, z, t; bool inq[NN]; char str[N][N]; const int dx[4] = {0, 1, 0, -1}, dy[4] = {-1, 0, 1, 0}; inline void add(int u, int v, int f, int c) { e[cnt].v = v; e[cnt].f = f; e[cnt].c = c; e[cnt].ne = head[u]; head[u] = cnt++; e[cnt].v = u; e[cnt].f = 0; e[cnt].c = -c; e[cnt].ne = head[v]; head[v] = cnt++; } bool spfa(int s, int t) { for (int i = 0; i <= t; i++) dis[i] = INF, inq[i] = 0, path[i] = -1; dis[s] = 0; inq[s] = 1; queue<int> que; que.push(s); while (!que.empty()) { int u = que.front(); que.pop(); inq[u] = 0; for (int i = head[u]; ~i; i = e[i].ne) { int v = e[i].v, c = e[i].c; if (e[i].f && dis[v] > dis[u] + c) { dis[v] = dis[u] + c; path[v] = i; if (!inq[v]) { inq[v] = 1; que.push(v); } } } } return dis[t] != INF; } int mcf(int s, int t) { int ans = 0; while (spfa(s, t)) { for (int i = path[t]; ~i; i = path[e[i ^ 1].v]) e[i].f--, e[i ^ 1].f++; ans += dis[t]; } return ans; } int main() { //freopen("in.txt", "r", stdin); memset(head, -1, sizeof(head)); scanf("%d%d%d%d", &n, &m, &z, &t); for (int i = 1; i <= n; i++) scanf("%s", str[i] + 1); for (int i = 1; i <= z; i++) { int x, y, p, q, h; scanf("%d%d%d%d%d", &x, &y, &p, &q, &h); for (int j = p; j < q; j++) checkmax(mp[x][y][j], h); } tol = 1; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) if (str[i][j] != '#') for (int k = 0; k < t; k++) { add(tol, tol + 1, 1, 0); //cout << tol << ' ' << tol + 1 << endl; id[i][j][k] = tol; tol += 2; } int S = tol + 1, T = tol + 2; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) if (id[i][j][0]) { for (int d = 0; d < 4; d++) if (id[i + dx[d]][j + dy[d]][0]) for (int k = 0; k < t - 1; k++) add(id[i][j][k] + 1, id[i + dx[d]][j + dy[d]][k + 1], 1, 0); for (int k = 0; k < t - 1; k++) add(id[i][j][k] + 1, id[i][j][k + 1], 1, -mp[i][j][k]); add(id[i][j][t - 1] + 1, T, 1, -mp[i][j][t - 1]); if (str[i][j] == 'S') add(S, id[i][j][0], 1, 0); } printf("%d\n", -mcf(S, T)); return 0; }