Description
一个 (n imes m) 的棋盘,每个格子里有一个 (0-9) 的数字。每次游戏可以选取一个没有经过的格子为起点跳任意多步,可以向右或向下跳到一个没有经过的点。每次跳需要消耗两点间的曼哈顿距离减一的能量,若每次跳的起点和终点的数字相同,可以获得该数字的能量。问 (k) 次或更少次游戏后,是否能访问整张图,若能输出最大能量。
(n,mle 10,kle 100)
Solution
完蛋了网络流水平大退化
费用流。
拆点,每个格子拆成 (x,y) ,连边 ((S,x,1,0)) , ((y,T,1,0)) ,如果格子 (i) 能一跳到达 (j) 则连边 ((x_i,y_j,1,消耗-所得)) 。
新建节点 (Q) ,连边 ((Q,y,1,0)) 。
为什么要这样建边呢?
咕咕咕
#include<bits/stdc++.h>
using namespace std;
template <class T> void read(T &x) {
x = 0; bool flag = 0; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) flag |= (ch == '-');
for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48; flag ? (x = -x) : 0;
}
#define N 500
#define rep(i, a, b) for (int i = (a); i <= (b); i++)
#define INF 0x3f3f3f3f
struct edge { int u, v, c, w, next; }e[100001];
int S, T, flow, cost, head[N], tot = 1, dis[N], pre[N];
queue<int> q;
bool inq[N];
inline void insert(int u, int v, int c, int w) { e[++tot].u = u, e[tot].v = v, e[tot].c = c, e[tot].w = w, e[tot].next = head[u], head[u] = tot; }
inline void add(int u, int v, int c, int w) { insert(u, v, c, w), insert(v, u, 0, -w); }
inline bool spfa() {
rep(i, S, T) dis[i] = INF; dis[S] = 0; q.push(S);
while (!q.empty()) {
int u = q.front(); q.pop(); inq[u] = 0;
for (int i = head[u], v, w; i; i = e[i].next) if (e[i].c > 0 && dis[v = e[i].v] > dis[u] + (w = e[i].w)) {
dis[v] = dis[u] + w, pre[v] = i;
if (!inq[v]) q.push(v); inq[v] = 1;
}
}
return dis[T] != INF;
}
inline void mcf() {
int d = INF;
for (int i = T; (i ^ S); i = e[pre[i]].u) d = min(d, e[pre[i]].c);
flow += d;
for (int i = T; (i ^ S); i = e[pre[i]].u) e[pre[i]].c -= d, e[pre[i] ^ 1].c += d, cost += d * e[pre[i]].w;
}
int a[N][N], n, m, K;
char s[N];
inline int x(int i, int j) { return (i - 1) * m + j; }
inline int y(int i, int j) { return x(i, j) + n * m; }
int main() {
int Case; read(Case);
rep(_Case, 1, Case) {
memset(head, 0, sizeof head), tot = 1;
read(n), read(m), read(K);
int Q = n * m * 2 + 1; S = 0, T = Q + 1;
rep(i, 1, n) {
scanf("%s", s + 1);
rep(j, 1, m) a[i][j] = s[j] - '0';
}
add(S, Q, K, 0);
rep(i, 1, n) rep(j, 1, m) {
add(S, x(i, j), 1, 0), add(y(i, j), T, 1, 0);
add(Q, y(i, j), 1, 0);
rep(k, j + 1, m) add(x(i, j), y(i, k), 1, k - j - 1 - (a[i][j] == a[i][k] ? a[i][j] : 0));
rep(k, i + 1, n) add(x(i, j), y(k, j), 1, k - i - 1 - (a[i][j] == a[k][j] ? a[i][j] : 0));
}
flow = 0, cost = 0;
while (spfa()) mcf();
printf("Case %d : %d
", _Case, (flow == n * m ? -cost : -1));
}
return 0;
}