poj3422 Kaka's Matrix Travels

Kaka's Matrix Travels
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 10171   Accepted: 4128

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
题目大意:从左上角走到右下角k次,收集走到的点的数字,每个数字只能收集一次,问最多可以收集多大的数字.
分析:k=2就是非常经典的dp问题了.k其实就是限制一个点最多只能走k次,网络流可以限制一条边走的次数,那么可以将边的情况变到点的情况上.对于每一个点,拆成两个点,这两个点之间连一条容量为走的次数的限制.因为要求权值,所以求的是费用流.
          容量问题解决了,但是费用问题不是很好办,一个点的数字只能被收集一次,那么最多只允许走一次费用为a[i][j]的边,剩下的k-1次只能走费用为0的边,那么对于每个点a拆成的两个点a',a'',从a'向a''连一条容量为1,费用为a[i][j]的边,再连一条容量为k - 1,费用为0的边,对于每个点被拆出的第二个点a'',向下一个能走到的点b'连一条容量为k,费用为0的边.最后跑最大费用最大流就可以了.在最小费用最大流上将spfa改成求最长路就可以了.
#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 50010,inf = 0x3f3f3f3f;
int n,k,a[60][60],head[maxn],to[maxn],nextt[maxn],tot = 2,w[maxn],c[maxn];
int S,T,d[maxn],vis[maxn],vis2[maxn],ans;

void add(int x,int y,int z,int p)
{
    w[tot] = z;
    c[tot] = p;
    to[tot] = y;
    nextt[tot] = head[x];
    head[x] = tot++;

    w[tot] = 0;
    c[tot] = -p;
    to[tot] = x;
    nextt[tot] = head[y];
    head[y] = tot++;
}

bool spfa()
{
    memset(vis,0,sizeof(vis));
    memset(vis2,0,sizeof(vis2));
    memset(d,-1,sizeof(d));
    queue <int> q;
    vis[S] = 1;
    d[S] = 0;
    q.push(S);
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = 0;
        for (int i = head[u];i;i = nextt[i])
        {
            int v = to[i];
            if (w[i] && d[v] < d[u] + c[i])
            {
                d[v] = d[u] + c[i];
                if (!vis[v])
                {
                    vis[v] = 1;
                    q.push(v);
                }
            }
        }
    }
    return d[T] != -1;
}

int dfs(int u,int f)
{
    if (u == T)
    {
        ans += f * d[u];
        return f;
    }
    int res = 0;
    vis2[u] = 1;
    for (int i = head[u];i;i = nextt[i])
    {
        int v = to[i];
        if (!vis2[v] && w[i] && d[v] == d[u] + c[i])
        {
            int temp = dfs(v,min(f - res,w[i]));
            res += temp;
            w[i] -= temp;
            w[i ^ 1] += temp;
            if (res == f)
                return res;
        }
    }
    return res;
}

void dinic()
{
    while (spfa())
        dfs(S,inf);
}

int main()
{
    scanf("%d%d",&n,&k);
    S = 0,T = n * n * 2 + 1;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
        {
            scanf("%d",&a[i][j]);
            int id = (i - 1) * n + j;
            add(id,id + n * n,1,a[i][j]);
            add(id,id + n * n,k - 1,0);
            int tx = i + 1,ty = j;
            if (tx <= n && ty <= n)
            {
                int nid = (tx - 1) * n + ty;
                add(id + n * n,nid,k,0);
            }
            tx = i,ty = j + 1;
            if (tx <= n && ty <= n)
            {
                int nid = (tx - 1) * n + ty;
                add(id + n * n,nid,k,0);
            }
        }
    add(S,1,k,0);
    add(n * n * 2,T,k,0);
    dinic();
    printf("%d
",ans);

    return 0;
}
原文地址:https://www.cnblogs.com/zbtrs/p/8149899.html