这个题建图的时候需要拆点。每个格子都是一个点。把一个点拆成两个,两个点之间有两条路,一个容量为1,权值为那个格子的金钱数。另一条路容量为k-1,权值为0。因为走了一次钱捡起来之后就没钱了。
超级源点是n*n*2, 超级汇点是n*n*2+1.
#include <iostream>
#include <queue>
#include <string.h>
using namespace std;
#define inf 1 << 30
#define M 5005
int n, m, countt, ans;
int map1[55][55], head[M], pre_node[M], distances[M];
bool visited[M];
struct node {
int u, v, weight, flow, next;
} edge[100005];
/**
* ADD EDGE, TIE THE POINT INTO TWO PARTS. FOR ONE OF THE PARTS, THE CAPACITY IS 1, THE WEIGHT IS THE MONEY;
* ANOTHER ONE, THE CAPACITY IS K-1, THE WEIGHT IS 0.
*
* @param u FORMER POINT
* @param v NEXT POINT
* @param w WEIGHT
* @param f FLOW
*/
void add(int u, int v, int w, int f) {
edge[countt].u = u;
edge[countt].v = v;
edge[countt].weight = w;
edge[countt].flow = f;
edge[countt].next = head[u];
head[u] = countt;
countt++;
edge[countt].u = v;
edge[countt].v = u;
edge[countt].weight = -w;
edge[countt].flow = 0;
edge[countt].next = head[v];
head[v] = countt;
countt++;
}
/**
* TEST IF THERE ARE SHORTEST PATH FROM SUPERSOURCE(N*N*2) TO SUPERSINK(N*N*2+1)
*
* @return TURE OR FALSE
*/
bool spfa() {
for (int i = 0; i <= n * n * 2 + 1; i++) {
pre_node[i] = -1;
distances[i] = inf;
visited[i] = false;
}
queue <int> q;
distances[n * n * 2] = 0;
visited[n * n * 2] = true;
q.push(n * n * 2);
int i;
while (!q.empty()) {
int t = q.front();
q.pop();
i = head[t];
visited[t] = false;
while (i != -1) {
if (edge[i].flow > 0 && distances[edge[i].v] > distances[t] + edge[i].weight) {
distances[edge[i].v] = distances[t] + edge[i].weight;
pre_node[edge[i].v] = i;
if (!visited[edge[i].v]) {
visited[edge[i].v] = true;
q.push(edge[i].v);
}
}
i = edge[i].next;
}
}
if (pre_node[n * n * 2 + 1] == -1) {
return false;
}
return true;
}
/**
* GET MAX FLOW, THEN ARGUE IT
*/
void getMaxflow() {
while (spfa()) {
int max1 = inf;
int p = pre_node[n * n * 2 + 1];
while (p != -1) {
max1 = min(max1, edge[p].flow);
p = pre_node[edge[p].u];
}
p = pre_node[n * n * 2 + 1];
while (p != -1) {
edge[p].flow -= max1;
edge[p ^ 1].flow += max1;
ans += max1 * edge[p].weight;
p = pre_node[edge[p].u];
}
}
}
int main() {
while (cin >> n >> m) {
int i, j;
countt = 0;
for (i = 1; i <= n; i++) {
for (j = 1; j <= n; j++) {
cin >> map1[i][j];
}
}
memset(head, -1, sizeof(head));
for (i = 1; i <= n; i++) {
for (j = 1; j <= n; j++) {
int u = (i - 1) * n + j - 1;
add(u * 2, u * 2 + 1, -map1[i][j], 1); //reversed
add(u * 2, u * 2 + 1, 0, m - 1);
}
}
for (i = 1; i <= n; i++) {
for (j = 1; j < n; j++) {
int u = (i - 1) * n + j - 1;
add(u * 2 + 1, (u + 1) * 2, 0, m);
}
}
for (i = 1; i < n; i++) {
for (j = 1; j <= n; j++) {
int u = (i - 1) * n + j - 1;
add(u * 2 + 1, (u + n) * 2, 0, m);
}
}
add(n * n * 2, 0, 0, m); //SuperSource
add(n * n * 2 - 1, n * n * 2 + 1, 0, m); //SuperSink
ans = 0;
getMaxflow();
cout << -ans << endl;
}
return 0;
}