zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    hdu 1024 Max Sum Plus Plus DP
    九月回顾 这篇文章和ACM毫无关系= =
    HDU 3974 Assign the task 并查集/图论/线段树
    poj 3264 Balanced Lineup RMQ问题
    zoj 1610 Count the Colors 线段树区间更新/暴力
    poj 3468 A Simple Problem with Integers 线段树区间加,区间查询和
    hdu 4027 Can you answer these queries? 线段树区间开根号,区间求和
    hdu 5195 DZY Loves Topological Sorting 线段树+拓扑排序
    codeforces 19D D. Points 树套树
    codeforces 85D D. Sum of Medians Vector的妙用
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8149899.html
Copyright © 2011-2022 走看看