zoukankan      html  css  js  c++  java
  • 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:

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

    不会写就加维度

     

  • 相关阅读:
    QComboBox实现复选功能
    STL容器介绍
    QTableWidget控件总结
    (转)QT常用快捷键
    Hibernate的CRUD
    理解O/R Mapping
    JQuery验证input
    MapReduce概念(转)
    RedHat9上安装jdk
    集合框架
  • 原文地址:https://www.cnblogs.com/Loizbq/p/7716640.html
Copyright © 2011-2022 走看看