P1004 方格取数

DP

题目链接:https://www.luogu.org/problem/show?pid=1004

题目大意:

    给你一个矩阵,有一些点上有数字,只能向右走或向下走,走过后这个点上的数字会变成0,从左上角到右下角走两次,所能得到的最大数字之和

 

A:如果不考虑走两次的话,会简单一点,那首先设计状态~

B:f[ i ][ j ] 表示从起点到 i,j 点 所能取得的数字和最大为f[ i ][ j ]

A:然后想想对于每个点他能由哪里直接推出来?

B:因为只能向右或向下,所以他一定是由左边或者上边走过来

A:走过来就加上这个点的数字?

A:然后:

            f[i][j] = max(f[i - 1][j],f[i][j - 1]) + mp[i][j];    

是这样么??
B:因为要走两遍,所以跑两次,然后第一次走过的都设成0不就可以了?

A:等等等等,两次的最优真的等同于一次同时考虑两个的最优么??(哈哈哈嗝,就是不告诉你答案~~)

(解释见下文)

END.

对于每一个点,都可以由左边或上边走过来

因为要走两遍所以可以看成是两个同时从左上角开始走

这样的话这样才能确定一种状态呢?

你需要同时知道两个点的坐标,是同时!!

设计状态:f[i][j][a][b] 为第一个点走到i,j 第二个点走到a,b时所能取到的最大数字和

(有5个量,把其中4个确定,另一个作为答案统计)

根据移动的规则,很容易就能推出方程来啦~

    f[i][j][a][b] = maxx(f[i - 1][j][a - 1][b],f[i - 1][j][a][b - 1],
                        f[i][j - 1][a][b - 1],f[i][j - 1][a - 1][b]);            

那怎么处理走过的情况呢?

因为只能向右走或向下走,

所以a路走到b路已走过的点时,

b路一定也在正这个点上,

也就是说,

他们一定是同时走到相同的点。(自己动手试试啦~)

那我们可以直接判两点是否是同一个点来判断是否走重。

好的,现在该注意的都分析了,

然后。。。贴代码??

当然不是不是不是!!

还记得小A的问题么(A:记得记得!)

为什么不能看成是两次最优的组合呢?

那是因为在同时考虑两条路时,不仅考虑了一条最优,

还考虑了在这条最优的路线之外还能尽量多的走过多少数字

而在考虑一条路时,可能会导致本来可以全取走的数没能取完

看数据看数据:

    样例输入:
    7
    1 3 2
    1 4 3
    2 3 3
    3 3 3
    5 5 4
    6 5 4
    7 3 2
    7 5 4
    0 0 0

    二维DP输出:23 
    四维DP输出:25

    方格示意图:
    0 0 2 3 0 0 0
    0 0 3 0 0 0 0
    0 0 3 0 0 0 0
    0 0 0 0 0 0 0
    0 0 0 0 4 0 0
    0 0 0 0 5 0 0
    0 0 2 0 4 0 0

嗯,这个题就是这样了

Codes:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>

using namespace std;
const int N = 10 + 5;
int n,mp[N][N];
int f[N][N][N][N],bo[N][N];
int maxx(int x,int y){
    if(x > y) return x;
    return y;
}
int main(){
    scanf("%d",&n);
    int a,b,c;
    for(;;){
        scanf("%d%d%d",&a,&b,&c);
        if(a == b && b == c && c == 0)    
            break;
        mp[a][b] = c;
    }
    for(int i = 1;i <= n;++ i){
        for(int j = 1;j <= n;++ j){
            for(int a = 1;a <= n;++ a){
                for(int b = 1;b <= n;++ b){
                    f[i][j][a][b] = maxx(f[i - 1][j][a - 1][b],f[i - 1][j][a][b - 1]);
                    f[i][j][a][b] = maxx(f[i][j][a][b],f[i][j - 1][a][b - 1]);
                    f[i][j][a][b] = maxx(f[i][j][a][b],f[i][j - 1][a - 1][b]);
                    if(i == a && j == b) 
                        f[i][j][a][b] += mp[i][j];
                    else f[i][j][a][b] += mp[i][j] + mp[a][b];
                /*    else if(!bo[i][j] || !bo[a][b]){           //之前的错误判法 
                        if(!bo[i][j]){
                            f[i][j][a][b] += mp[i][j];
                        }
                        if(!bo[a][b]){
                            f[i][j][a][b] += mp[a][b];
                        }
                        bo[i][j] = bo[a][b] = 1;
                    }*/
                //    cout << f[i][j][a][b] << '
';
                }
            }
        }
    }
    cout << f[n][n][n][n] << '
';
    return 0;
}

 MAS:

考虑思路的正确性?(好吧这很重要)

不会写就加维度

 

原文地址:https://www.cnblogs.com/Loizbq/p/7716640.html