zoukankan      html  css  js  c++  java
  • TZOJ4777: 方格取数

    4777: 方格取数 分享至QQ空间

    Time Limit(Common/Java):1000MS/3000MS     Memory Limit:65536KByte
    Total Submit: 11            Accepted:10

    Description

     

    设有N*N的方格图(N<=10,我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0。如下图所示(见样例):

     

    某人从图的左上角的A 点出发,可以向下行走,也可以向右走,直到到达右下角的B点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。

    此人从A点到B 点共走两次,试找出2条这样的路径,使得取得的数之和为最大。

     

    Input

     

    输入的第一行为一个整数N(表示N*N的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的0表示输入结束。

    Output

     

    只需输出一个整数,表示2条路径上取得的最大的和。

    Sample Input 

    8
    2 3 13
    2 6 6
    3 5 7
    4 4 14
    5 2 21
    5 6 4
    6 3 15
    7 2 14
    0 0 0

    Sample Output

    67 

    我觉得大家第一反应应该都是做一次DP之后再做一次,但是这是在贪心,这次走完最大值的路径下次就不走了

    所以其实要一起考虑,算法复杂度是n^3,它是有四个点的,包括前一次经过的点,而且步数的几个点是确定的,在一条斜线上

    #include <bits/stdc++.h>
    using namespace std;
    #define max4(a, b, c, d) max(max(a, b), max(c, d))
    int dp[21][11][11];
    int a[11][11];
    int main()
    {
        int n, x, y, z;
        scanf("%d", &n);
        while (~scanf("%d%d%d", &x, &y, &z) && (x || y || z))a[x][y] = z;
        for (int k = 1; k < n * 2; k++)
            for (int i = 1; i <= n; i++)
                for (int j = 1; j <= n; j++)
                {
                    if (i > k || j > k || k - j + 1 > n || k - i + 1 > n)continue;
                    dp[k][i][j] = max4(dp[k - 1][i][j], dp[k - 1][i - 1][j], dp[k - 1][i][j - 1], dp[k - 1][i - 1][j - 1]);
                    dp[k][i][j] += a[k - j + 1][j];
                    if (i != j)dp[k][i][j] += a[k - i + 1][i];
                }
        cout << dp[n * 2 - 1][n][n];
        return 0;
    }

    升级版的k步,需要使用最大流求解

    首先拆点,将一个点拆成x和y,然后从x到y连一条容量为1,流量为x的边

    然后再连一条容量为inf,费用为0的边

    这样即可保证一个点可以走多次,而数只能取一次。然后连接a和b时,从a的y向b的x连一条容量为inf,费用为0的边。最后跑最大费用最大流即可。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 1e4 + 5;
    const int M = 1e5 + 5;
    const int INF = 0x3f3f3f3f;
    
    int FIR[N], TO[M], CAP[M], FLOW[M], COST[M], NEXT[M], tote;
    int pre[N], dist[N], q[400000];
    bool vis[N];
    int n, k, S, T;
    void init()
    {
        tote = 0;
        memset(FIR, -1, sizeof(FIR));
    }
    void add(int u, int v, int cap, int cost)
    {
        TO[tote] = v;
        CAP[tote] = cap;
        FLOW[tote] = 0;
        COST[tote] = cost;
        NEXT[tote] = FIR[u];
        FIR[u] = tote++;
    
        TO[tote] = u;
        CAP[tote] = 0;
        FLOW[tote] = 0;
        COST[tote] = -cost;
        NEXT[tote] = FIR[v];
        FIR[v] = tote++;
    }
    bool SPFA(int s, int t)
    {
        memset(dist, INF, sizeof(dist));
        memset(vis, false, sizeof(vis));
        memset(pre, -1, sizeof(pre));
        dist[s] = 0;
        vis[s] = true;
        q[1] = s;
        int head = 0, tail = 1;
        while (head != tail)
        {
            int u = q[++head];
            vis[u] = false;
            for (int v = FIR[u]; v != -1; v = NEXT[v])
            {
                if (dist[TO[v]] > dist[u] + COST[v] && CAP[v] > FLOW[v])
                {
                    dist[TO[v]] = dist[u] + COST[v];
                    pre[TO[v]] = v;
                    if (!vis[TO[v]])
                    {
                        vis[TO[v]] = true;
                        q[++tail] = TO[v];
                    }
                }
            }
        }
        return pre[t] != -1;
    }
    void MCMF(int s, int t, int &cost, int &flow)
    {
        flow = cost = 0;
        while (SPFA(s, t))
        {
            int Min = INF;
            for (int v = pre[t]; v != -1; v = pre[TO[v ^ 1]])
                Min = min(Min, CAP[v] - FLOW[v]);
            for (int v = pre[t]; v != -1; v = pre[TO[v ^ 1]])
            {
                FLOW[v] += Min;
                FLOW[v ^ 1] -= Min;
                cost += COST[v] * Min;
            }
            flow += Min;
        }
    }
    int main()
    {
        int ca;
        cin>>ca;
        while(ca--)
        {
            init();
            cin >> n >> k;
            S = 0;
            T = n * n * 2 + 1;
            int ff=n*n;
            for (int i = 1; i <= n; i++)
            for (int j = 1, x; j <= n; j++)
            {
                cin>>x;
                int a=(i-1)*n+j,b=a+1,c=a+n;
                add(a,ff+a,INF,0),add(a,ff+a,1,-x);
                if(j<n)add(ff+a,b,INF,0);
                if(i<n)add(ff+a,c,INF,0);
            }
            add(S, 1, k, 0);
            add(T - 1, T, k, 0);
            int cost, flow;
            MCMF(S, T, cost, flow);
            printf("%d
    ", -cost);
        }
        return 0;
    }

     

     

  • 相关阅读:
    mac shell终端编辑命令行快捷键——行首行尾
    mac appium 启动genymotion
    mac eclipse 执行adb 命令,提示command not fount
    java jsch 登录linux系统避免手动输入Yes 或Always
    mac 安装android sdk
    内容选择器
    增强基本选择器[selector_3.html]
    层次选择器[selector_2.html]
    基本选择器
    jquery 入门与知识
  • 原文地址:https://www.cnblogs.com/BobHuang/p/11191793.html
Copyright © 2011-2022 走看看