[Acwing] 算法提高课汇总一 动态规划- 数字三角形模型

数字三角形模型

1. 摘花生

就是最基础的数字三角形模型

状态表示 :
f [ i ] [ j ] f[i][j] f[i][j]表示当前 ( i , j ) (i,j) (i,j)的最大价值

状态转移 :
f [ i ] [ j ] = m a x ( f [ i − 1 ] [ j ] , f [ i ] [ j − 1 ] ) f[i][j] = max(f[i-1][j],f[i][j-1]) f[i][j]=max(f[i1][j],f[i][j1])

2.最低通行费

这个题还是最基础的数字三角形模型

只是变向的问了

对于一个 N × N N×N N×N的网格,限定 2 N − 1 2N-1 2N1步走出去

根据曼哈顿距离,我们可以知道如果只往下和右走,那么所需的距离正好就是 2 N − 1 2N-1 2N1

因此问题又回到了那个模板的问题

3.方格取数

题意 :
对于方格 ( i , j ) (i,j) (i,j)都赋予一个 w i , j w_{i,j} wi,j

试问类似摘花生那种做法,做两次的最大值

拿完之后该点的权值为0

思路 :
如果分开走的话,那么第一次走完之后会有后效性影响第二次拿的价值,所以必须同时走

状态表示 :
f [ i 1 ] [ j 1 ] [ i 2 ] [ j 2 ] f[i_1][j_1][i_2][j_2] f[i1][j1][i2][j2]表示同时分别走到 从 ( 1 , 1 ) 开 始 走 到 ( i 1 , j 1 ) ( i 2 , j 2 ) 从(1,1)开始走到(i_1,j_1)(i_2,j_2) (1,1)(i1,j1)(i2,j2)的路径的集合

状态计算 :
f [ i 1 ] [ j 1 ] [ i 2 ] [ j 2 ] = m a x ( f[i_1][j_1][i_2][j_2]=max( f[i1][j1][i2][j2]=max(

f [ i 1 − 1 ] [ j 1 ] [ i 2 − 1 ] [ j 2 ] − 从 上 面 转 移 f[i_1-1][j_1][i_2-1][j_2] -从上面转移 f[i11][j1][i21][j2]
f [ i 1 ] [ j 1 − 1 ] [ i 2 − 1 ] [ j 2 ] − 从 左 边 和 上 面 转 移 f[i_1][j_1-1][i_2-1][j_2] -从左边和上面转移 f[i1][j11][i21][j2]
f [ i 1 ] [ j 1 − 1 ] [ i 2 ] [ j 2 − 1 ] − 从 左 边 转 移 f[i_1][j_1-1][i_2][j_2-1] -从左边转移 f[i1][j11][i2][j21]
f [ i 1 − 1 ] [ j 1 ] [ i 2 ] [ j 1 − 1 ] − 从 上 面 和 左 边 转 移 ) f[i_1-1][j_1][i_2][j_1-1] - 从上面和左边转移) f[i11][j1][i2][j11])

当然因为拿完就置 0 0 0的存在,我们需要考虑 ( i 1 , j 1 ) ( i 2 , j 2 ) (i_1,j_1)(i_2,j_2) (i1,j1)(i2,j2)是否是相同的格子

因此我们可以做一个优化

我们令 k = i 1 + j 1 = i 2 + j 2 k=i_1+j_1=i_2+j_2 k=i1+j1=i2+j2

我们只需要 n ∗ 2 n*2 n2的枚举 k k k以及枚举 i 1 i_1 i1, i 2 i_2 i2然后通过计算出来 j 1 j_1 j1 j 2 j_2 j2即可

最后判断是否相同

const int N = 15;

int n;
int w[N][N], f[N*2][N][N];

int main() {
    cin >> n;

    int a,b,c;
    while(cin >> a >> b >> c, a || b || c) w[a][b] = c;

    for(int k = 2; k <= 2*n; k++) {
        for(int i1 = 1; i1 <= n; i1++) {
            for(int i2 = 1; i2 <= n; i2++) {
                int j1 = k-i1, j2 = k-i2;
                if(j1>=1&&j1<=n&&j2>=1&&j2<=n) {
                    // 不能越界
                    int &x = f[k][i1][i2];
                    int t = w[i1][j1];
                    if(i1!=i2) t += w[i2][j2];
                    //不重合则需要加两个权重.
                    x = max(x, f[k-1][i1-1][i2-1]+t);
                    x = max(x, f[k-1][i1-1][i2]+t);
                    x = max(x, f[k-1][i1][i2-1]+t);
                    x = max(x, f[k-1][i1][i2]+t);
                    //保留最大属性
                }
            }
        }
    }

    cout << f[n*2][n][n] << endl;
4.传纸条

这里和前面的方格取数不一样的是

方格取数是从同一个起点开始,但是这里是从两个对角开始

并且走过的点不能再回走

思路 :
证明出来,最优的路径显然不是两个相交路径之和,同时又因为从右下角回传可用对称等效为从左上角传

所以完全可用套用方格取数模板

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值