P1216 [IOI1994][USACO1.5]数字三角形 Number Triangles

P1216 [IOI1994][USACO1.5]数字三角形 Number Triangles

这个题吧,之前学DP的时候就做过一次了,其实还是挺简单的,如果一步一步按照找状态定义,找边界条件,找转移方程的话,不失为一道好题,我们就就这题复习一下DP,然后顺便讲点别的

因为我们是从顶点开始走,往左下走或者右下走,所以我们的状态就是F[i][j]我们停在第i行第j列所能达到的最大权值

对于每一个点,我们看他是从哪一个点过来的,可以是右上面也可以是左上面

 转移方程:f[i][j]=max(f[i-1][j-1]+f[i-1][j])+a[i][j]

QWQ终于是有一个能码出来的代码了

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int r,a[1001][1001],qaq[1001][1001],MAX;
int main() {
    cin>>r;
    for(int i=1; i<=r; ++i)//第i行第j个
        for(int j=1; j<=i; ++j)
            cin>>a[i][j];
    for(int i=1; i<=r; ++i)
        for(int j=1; j<=i; ++j) {
            qaq[i][j]=max(qaq[i-1][j-1],qaq[i-1][j])+a[i][j];
        }
    for(int i=1; i<=r; ++i)
        MAX=max(MAX,qaq[r][i]);
        cout<<MAX;
    return 0;
}

改造题目(EX NumberTriangles)

我们要使得找出来的权值和%m之后的值是最大的,

起初我的想法是用一个结构体来存实际权值和取模后的权值,但是是不行的,因为不再满足最优子结构原则了。(就是说实际权值和取模权值之间的大小没有必然联系,所以我们无法用状态转移方程来求最大最小)

我们考虑加一个维度,开一个bool数组f

f[i][j][k]代表走到第i行第j列是路径权值和%m=  k    可不可能,那我们怎么转移呢

还是考虑一个点只有可能从它的左上方和右上方求值过来,那么我们就能得出状态转移方程了

f[i][j][k] = f[i - 1][j - 1][(k - a[i][j]) % m] || f[i - 1][j][(k - a[i][j]) % m]
边界情况的话,就是
f[1][1][a[1][1] % m] = true(按照状态的定义来理解就行,很好理解)
然后我们就遍历一遍最终结果就可以了
for (int i = 1; i <= n; ++i)
    {
        for (int j = 1; j <= m; ++j)
        {
            if (f[n][i][j])
                ans = max(ans, j);
        }
    }

就这样,完事(大雾)

posted @ 2019-04-30 20:04  Emiya_Shirou  阅读(269)  评论(0编辑  收藏  举报