zoukankan      html  css  js  c++  java
  • luogu 1004 方格取数 dp

    题目链接

    题意

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

    A
     0  0  0  0  0  0  0  0
     0  0 13  0  0  6  0  0
     0  0  0  0  7  0  0  0
     0  0  0 14  0  0  0  0
     0 21  0  0  0  4  0  0
     0  0 15  0  0  0  0  0
     0 14  0  0  0  0  0  0
     0  0  0  0  0  0  0  0
                            B
    

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

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

    思路

    如果采取走两次分别保证最优的做法,得到的答案不一定总和最优。

    正解是考虑三重循环,模拟两个人同时向前走。最外层循环为当前已走的步数,里面两层循环分别为第一个人走到的行数和第二个人走到的行数。即(dp[k][i][j])表示当前走了(k)步,第一个人的坐标为((i,k-i)),第二个人的坐标为((j,k-j)).

    又因为第(k+1)步只可能由第(k)步转移过来,因此可以采取类似背包问题的简化方式,将第一维省去。

    这种外层循环为步数,逐步向前走的做法,保证了不会出现一个人走到另一个人以前走过的路径上的情况,路径重合只可能发生在当前走到同一个格子上,而这种情况是很好处理的,计算一次即可。
    // 讲道理我不是很明白那些写四重循环的为什么是对的。

    Code

    #include <bits/stdc++.h>
    #define maxn 10
    using namespace std;
    typedef long long LL;
    int a[maxn][maxn], dp[maxn][maxn];
    int main() {
        int n, x, y, k;
        scanf("%d", &n);
        while (scanf("%d%d%d", &x, &y, &k) && x) a[x][y] = k;
        for (int k = 2; k <= (n<<1); ++k) {
            for (int i = min(k-1, n); i >= 1; --i) {
                for (int j = min(k-1, n); j >= 1; --j) {
                    dp[i][j] = max(dp[i-1][j-1], max(dp[i-1][j], max(dp[i][j-1], dp[i][j]))) + a[i][k-i] + (i!=j)*a[j][k-j];
                }
            }
        }
        printf("%d
    ", dp[n][n]);
        return 0;
    }
    
    
  • 相关阅读:
    Django之Form组件
    随笔——python截取http请求报文响应头
    django文件上传
    django框架(View)
    s15day14 ssh秘钥远程连接
    Python开发【第十九篇】:Python操作MySQL
    s15day12作业:MySQL练习题参考答案
    python+django+wusgi+nginx安装部署
    Python之路【第二十四篇】:Python学习路径及练手项目合集
    gideros-with-zerobrane
  • 原文地址:https://www.cnblogs.com/kkkkahlua/p/7632540.html
Copyright © 2011-2022 走看看