POJ 3422 Kaka's Matrix Travels

时间:2021-09-10 14:04:42
Kaka's Matrix Travels
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 9567   Accepted: 3888

Description

On an N × N chessboard with a non-negative number in each grid, Kaka starts his matrix travels with SUM = 0. For each travel, Kaka moves one rook from the left-upper grid to the right-bottom one, taking care that the rook moves only to the right or down. Kaka adds the number to SUM in each grid the rook visited, and replaces it with zero. It is not difficult to know the maximum SUM Kaka can obtain for his first travel. Now Kaka is wondering what is the maximum SUM he can obtain after his Kth travel. Note the SUM is accumulative during the K travels.

Input

The first line contains two integers N and K (1 ≤ N ≤ 50, 0 ≤ K ≤ 10) described above. The following N lines represents the matrix. You can assume the numbers in the matrix are no more than 1000.

Output

The maximum SUM Kaka can obtain after his Kth travel.

Sample Input

3 2
1 2 3
0 2 1
1 4 2

Sample Output

15

Source

POJ Monthly--2007.10.06, Huang, Jinsong

[Submit]   [Go Back]   [Status]   [Discuss]

有一个NxN的棋盘,每个格子有一个非负整数。从左上角走到右下角,获得路径格子上的权值(只能向右或向下走),且每个格子的权值只能获得一次,可以理解为经过的格子权值置为0。可以走K次,求获得的最大权值和。

拆点跑最大费用最大流。

每个格子拆成入点和出点,入点向出点连一条容量为1,权值为格子权值的边,表示权值只能获得一次,再连一条容量无穷,权值为0的的边,表示之后可以经过但不获得权值。再按照右下的转移规则连接格子即可。做从左上格子到右下格子,最大流为K的最大费用流即可。

 #include <cstdio>
#include <cstring> #define fread_siz 1024 inline int get_c(void)
{
static char buf[fread_siz];
static char *head = buf + fread_siz;
static char *tail = buf + fread_siz; if (head == tail)
fread(head = buf, , fread_siz, stdin); return *head++;
} inline int get_i(void)
{
register int ret = ;
register int neg = false;
register int bit = get_c(); for (; bit < ; bit = get_c())
if (bit == '-')neg ^= true; for (; bit > ; bit = get_c())
ret = ret * + bit - ; return neg ? -ret : ret;
} inline int min(int a, int b)
{
return a < b ? a : b;
} const int inf = 2e9; const int N = ;
const int M = ; int n, m;
int s, t;
int edges;
int hd[M];
int nt[M];
int to[M];
int fl[M];
int vl[M]; int dis[M];
int pre[M]; inline bool bfs(void)
{
static int que[M];
static int inq[M];
static int head, tail; memset(dis, -, sizeof(dis));
memset(inq, , sizeof(inq));
head = , tail = ;
que[tail++] = s;
pre[s] = -;
dis[s] = ;
inq[s] = ; while (head != tail)
{
int u = que[head++], v; inq[u] = ;
for (int i = hd[u]; ~i; i = nt[i])
if (dis[v = to[i]] < dis[u] + vl[i] && fl[i])
{
pre[v] = i ^ ;
dis[v] = dis[u] + vl[i];
if (!inq[v])inq[que[tail++] = v] = ;
}
} return dis[t] != -;
} inline int minCost(void)
{
int cost = ; while (bfs())
{
int flow = inf; for (int i = pre[t]; ~i; i = pre[to[i]])
flow = min(flow, fl[i ^ ]); for (int i = pre[t]; ~i; i = pre[to[i]])
fl[i] += flow, fl[i ^ ] -= flow; cost += dis[t] * flow;
} return cost;
} inline void add(int u, int v, int f, int w)
{
nt[edges] = hd[u]; to[edges] = v; fl[edges] = f; vl[edges] = +w; hd[u] = edges++;
nt[edges] = hd[v]; to[edges] = u; fl[edges] = ; vl[edges] = -w; hd[v] = edges++;
} int G[N][N]; inline int h(int x, int y, int k)
{
return ((x - ) * n + y) << | k;
} signed main(void)
{
n = get_i();
m = get_i(); for (int i = ; i <= n; ++i)
for (int j = ; j <= n; ++j)
G[i][j] = get_i(); memset(hd, -, sizeof(hd)); s = , t = (n*n + ) << | ; for (int i = ; i <= n; ++i)
for (int j = ; j <= n; ++j)
add(h(i, j, ), h(i, j, ), m, ),
add(h(i, j, ), h(i, j, ), , G[i][j]); for (int i = ; i < n; ++i)
for (int j = ; j <= n; ++j)
add(h(i, j, ), h(i + , j, ), m, ); for (int i = ; i <= n; ++i)
for (int j = ; j < n; ++j)
add(h(i, j, ), h(i, j + , ), m, ); add(s, h(, , ), m, );
add(h(n, n, ), t, m, ); printf("%d\n", minCost());
}

@Author: YouSiki