CODEVS 1227 方格取数 2

题目描述 Description

给出一个n*n的矩阵,每一格有一个非负整数Aij,(Aij <= 1000)现在从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0,这样一共走K次,现在要求K次所达到的方格的数的和最大

输入描述 Input Description

第一行两个数n,k(1<=n<=50, 0<=k<=10)

接下来n行,每行n个数,分别表示矩阵的每个格子的数

输出描述 Output Description

一个数,为最大和

样例输入 Sample Input

3 1

1 2 3

0 2 1

1 4 2

样例输出 Sample Output

11

数据范围及提示 Data Size & Hint

1<=n<=50, 0<=k<=10

Solution

经典的建图,把每个点拆成入点和出点,入点出点建连边,一条流量为1,费用为-w(最大费用),一条容量为k,费用为0(重复走),出点入点连边,容量k,费用0。S连到左上角的入点,右下角的出点连到T,费用为0,流量为k。

然后跑最大费用最大流,答案取负输出即可。

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include <cstdio>
#include <queue>
int getint() {
	int r = 0, k = 1; char c = getchar();
	for (; c < '0' || c > '9'; c = getchar()) if (c == '-') k = -1;
	for (; '0' <= c && c <= '9'; c = getchar()) r = r * 10 - '0' + c;
	return r * k;
}
const int maxn = 55;
const int maxe = 20005;
const int maxnode = 6005;
const int dx[2] = {0, 1}, dy[2] = {1, 0};
struct edge_type {
	int to, next, r, c;
} edge[maxe];
int h[maxnode], cnte = 1;
int S, T, tot = 2;
int n, m;
int w[maxn][maxn], rid[maxn][maxn], cid[maxn][maxn];
void ins(int u, int v, int f, int c) {
	++cnte;
	edge[cnte].to = v;
	edge[cnte].next = h[u];
	edge[cnte].r = f;
	edge[cnte].c = c;
	h[u] = cnte;
	++cnte;
	edge[cnte].to = u;
	edge[cnte].next = h[v];
	edge[cnte].r = 0;
	edge[cnte].c = -c;
	h[v] = cnte;
}
using namespace std;
const int INF = 1<<30;
queue<int> Q;
int dis[maxnode], pre[maxnode], a[maxnode];
bool vis[maxnode];
bool SPFA(int S, int T, int &flow, int &cost){
	while (!Q.empty()) Q.pop();
	for (int i = S; i <= T; ++i) vis[i] = false, dis[i] = INF;
	dis[S] = 0;
	Q.push(S);
	vis[S] = true;
	a[S] = INF;
	pre[S] = 0;
	int now;
	while (!Q.empty()) {
		now = Q.front(); Q.pop();
		vis[now] = false;
		for (int i = h[now]; i; i = edge[i].next) {
			if (edge[i].r && dis[edge[i].to] > dis[now] + edge[i].c) {
				dis[edge[i].to] = dis[now] + edge[i].c;
				pre[edge[i].to] = i;
				a[edge[i].to] = min(a[now], edge[i].r);
				if (!vis[edge[i].to]) {
					Q.push(edge[i].to);
					vis[edge[i].to] = true;
				}
			}
		}
	}
	if (dis[T] == INF) return false;
	flow += a[T];
	cost += a[T] * dis[T];
	for (now = T; now != S; now = edge[pre[now]^1].to) {
		edge[pre[now]].r -= a[T];
		edge[pre[now]^1].r += a[T];
	}
	return true;
}
int MCMF(int S, int T) {
	int flow = 0, cost = 0;
	while (SPFA(S, T, flow, cost));
	return cost;
}
int main() {
	n = getint(); m = getint(); S = 1;
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= n; ++j) {
			w[i][j] = getint();
			rid[i][j] = tot++;
			cid[i][j] = tot++;
			ins(rid[i][j], cid[i][j], 1, -w[i][j]);
			ins(rid[i][j], cid[i][j], m-1, 0);
		}
	T = tot;
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= n; ++j)
			for (int k = 0; k < 2; ++k) {
				int tx = i + dx[k], ty = j + dy[k];
				if (1<=tx&&tx<=n&&1<=ty&&ty<=n) ins(cid[i][j], rid[tx][ty], m, 0);
			}
	ins(S, rid[1][1], m, 0);
	ins(cid[n][n], T, m, 0);
	int ans = MCMF(S, T);
	printf("%d", -ans);
}