poj 3422 Kaka's Matrix Travels
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 9962 | Accepted: 4050 |
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
题意:从正方形矩阵的左上角走到终点右下角,中途只能往右走或者往下走,走到终点算走完一遍,现在棋盘每一个位置上都有相应的数字,走到相应的格子中则累加该数字,之后棋盘上该位置处数字变0。某人按规则一共在棋盘上走完了K次,问走了K次后累加的和sum最大为多少。
思路:棋盘每个格点可以拆成两个格点来建图,两个格点之间连两条边,一条流量为1,费用开始该格点上的数字的相反数,代表第一次走的时候往这条边走,可以使用一次该点上的数字,另一条边流量K,费用0,代表第二次或者以后再走这条边,就不能再累加该点上的数字。
之后建立源汇点,求最小费用最大流,求得的是负的最小值,相反数为正的最大值。
AC代码:
#define _CRT_SECURE_NO_DEPRECATE #include<iostream> #include<algorithm> #include<queue> #include<set> #include<vector> #include<cstring> #include<string> #include<functional> #include<cmath> using namespace std; #define INF 0x3f3f3f3f const int N_MAX = 50+4, V_MAX = 2*N_MAX*N_MAX+2; typedef pair<int, int>P; struct edge { int to, cap, cost, rev; edge(int to = 0, int cap = 0, int cost = 0, int rev = 0) :to(to), cap(cap), cost(cost), rev(rev) {} }; int V; vector<edge>G[V_MAX]; int h[V_MAX]; int dist[V_MAX]; int prevv[V_MAX], preve[V_MAX]; void add_edge(int from, int to, int cap, int cost) { G[from].push_back(edge(to, cap, cost, G[to].size())); G[to].push_back(edge(from, 0, -cost, G[from].size() - 1)); } //没流量则返回-1 int min_cost_flow(int s, int t, int f) { int res = 0; fill(h, h + V, 0); while (f>0) { priority_queue<P, vector<P>, greater<P> >que; fill(dist, dist + V, INF); dist[s] = 0; que.push(P(0, s)); while (!que.empty()) { P p = que.top(); que.pop(); int v = p.second; if (dist[v] < p.first)continue; for (int i = 0; i < G[v].size(); i++) { edge&e = G[v][i]; if (e.cap > 0 && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to]) { dist[e.to] = dist[v] + e.cost + h[v] - h[e.to]; prevv[e.to] = v; preve[e.to] = i; que.push(P(dist[e.to], e.to)); } } } if (dist[t] == INF)return -1; for (int v = 0; v < V; v++)h[v] += dist[v]; int d = f; for (int v = t; v != s; v = prevv[v]) { d = min(d, G[prevv[v]][preve[v]].cap); } f -= d; res += d*h[t]; for (int v = t; v != s; v = prevv[v]) { edge&e = G[prevv[v]][preve[v]]; e.cap -= d; G[v][e.rev].cap += d; } } return res; } void clear() { for (int i = 0; i < V; i++) { G[i].clear(); } } int N, K; int change(int x,int y) { return 2 * (N*y + x) + 1; } int main() { while (scanf("%d%d",&N,&K)!=EOF) { int s = 0, t = 2 * N*N + 1; V = t+1; add_edge(s,1,K,0); add_edge(t - 1, t, K, 0); for (int i = 0; i < N;i++) { for (int j = 0; j < N;j++) { int a; scanf("%d",&a); int cur = change(i, j); add_edge(cur,cur+1,1,-a); add_edge(cur, cur + 1, K, 0); if (i + 1 < N) {//向下连边 int down = change(i + 1, j); add_edge(cur+1,down,K,0); } if (j + 1 < N) {//向右连边 int left = change(i,j+1); add_edge(cur+1,left,K,0); } } } printf("%d\n",-min_cost_flow(s,t,K)); clear(); } return 0; }