动态规划DP 数字三角型模型 方格取数(题目详解+C++代码实现)

方格取数

原题链接

AcWing 1027. 方格取数

题目描述

设有 N×N 的方格图,我们在其中的某些方格中填入正整数,而其它的方格中则放入数字0。

如下图所示:

某人从图中的左上角 A 出发,可以向下行走,也可以向右行走,直到到达右下角的 B 点。

在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。

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

输入格式

第一行为一个整数N,表示 N×N 的方格图。

接下来的每行有三个整数,第一个为行号数,第二个为列号数,第三个为在该行、该列上所放的数。

行和列编号从 1开始。

一行"0 0 0"表示结束。

输出格式

输出一个整数,表示两条路径上取得的最大的和。

数据范围

N≤10

输入样例:

8
2 3 13
2 6 6
3 5 7
4 4 14
5 2 21
5 6 4
6 3 15
7 2 14
0 0 0

输出样例:

67

题目分析

摘花生 类似,不同点在于该题方格取数 要找出两条路径,使其和最大

回忆 摘花生 动态规划数字三角形模型思考。

摘花生(只走一次):
f [ i , j ] f[i,j] f[i,j] 表示左右从 ( 1 , 1 ) (1,1) (1,1) 走到 ( i , j ) (i,j) (i,j) 的路径的最大值
f [ i , j ] = m a x ( f [ i − 1 , j ] + w [ i ] [ j ] , f [ i , j − 1 ] + w [ i , j ] ) f[i,j]=max(f[i-1,j]+w[i][j],f[i,j-1]+w[i,j]) f[i,j]=max(f[i−1,j]+w[i][j],f[i,j−1]+w[i,j])

方格取数(走两次):

利用摘花生的思想,同时维护两条路径 ,用 f [ i 1 , j 1 , i 2 , j 2 ] f[i1,j1,i2,j2] f[i1,j1,i2,j2] 表示所有从 ( 1 , 1 ) , ( 1 , 1 ) (1,1), (1,1) (1,1),(1,1) 分别走到 ( i 1 , j 1 ) , ( i 2 , j 2 ) (i1,j1), (i2,j2) (i1,j1),(i2,j2) 的路径的最大值。

同时,每走一格,要么是 i + 1 i+1 i+1,要么是 j + 1 j+1 j+1,并且由于是同时出发的两条路径 ,则一定满足** i 1 + j 1 = i 2 + j 2 i1+j1=i2+j2 i1+j1=i2+j2** 。据此,我们可以化简状态 f [ i 1 , j 1 , i 2 , j 2 ] f[i1,j1,i2,j2] f[i1,j1,i2,j2],令 k = i 1 + j 1 = i 2 + j 2 k=i1+j1=i2+j2 k=i1+j1=i2+j2 ,表示两条路径走到的格子的横纵坐标之和
f [ k , i 1 , i 2 ] f[k,i1,i2] f[k,i1,i2] 表示所有从 ( 1 , 1 ) , ( 1 , 1 ) (1,1), (1,1) (1,1),(1,1) 分别走到 ( i 1 , k − i 1 ) , ( i 2 , k − i 2 ) (i1,k-i1), (i2,k-i2) (i1,k−i1),(i2,k−i2) 的路径的最大值。

但需要注意的是,当两条路径走到同一个格子时,一个方格中的数字只能被取一次,则如何处理"同一个格子不能被重复选择 "?

我们知道,只有在 i 1 + j 1 = i 2 + j 2 i1+j1=i2+j2 i1+j1=i2+j2 时,两条路径的格子才可能重合。即为在同一个 k k k 下,同时满足 i 1 = i 2 i1=i2 i1=i2 时,两条路径的格子重合。此时,该方格内的数字只被加一次

状态计算

用 t t t 表示下一步需要取的数字之和,
若两条路径不重合,则 t = w [ i 1 ] [ j 1 ] + w [ i 2 ] [ j 2 ] t=w[i1][j1]+w[i2][j2] t=w[i1][j1]+w[i2][j2],
若两条路径重合,则 t = w [ i 1 ] [ j 1 ] t=w[i1][j1] t=w[i1][j1](只用加一次)。

状态的转移计算示意图如下:

路径从左至右:则由 i − 1 i-1 i−1至 i i i,由 k − 1 k-1 k−1至 k k k。

路径从上至下:则 i i i 不变,由 k − 1 k-1 k−1至 k k k。

第一条路径:从左至右;第二条路径:从左至右:
f [ k ] [ i 1 ] [ i 2 ] = m a x ( f [ k ] [ i 1 ] [ i 2 ] , f [ k − 1 ] [ i 1 − 1 ] [ i 2 − 1 ] + t ) f[k][i1][i2]=max(f[k][i1][i2], f[k-1][i1-1][i2-1]+t) f[k][i1][i2]=max(f[k][i1][i2],f[k−1][i1−1][i2−1]+t)

第一条路径:从左至右;第二条路径:从上至下:
f [ k ] [ i 1 ] [ i 2 ] = m a x ( f [ k ] [ i 1 ] [ i 2 ] , f [ k − 1 ] [ i 1 − 1 ] [ i 2 ] + t ) f[k][i1][i2]=max(f[k][i1][i2], f[k-1][i1-1][i2]+t) f[k][i1][i2]=max(f[k][i1][i2],f[k−1][i1−1][i2]+t)

第一条路径:从上至下;第二条路径:从上至下:
f [ k ] [ i 1 ] [ i 2 ] = m a x ( f [ k ] [ i 1 ] [ i 2 ] , f [ k − 1 ] [ i 1 ] [ i 2 ] + t ) f[k][i1][i2]=max(f[k][i1][i2], f[k-1][i1][i2]+t) f[k][i1][i2]=max(f[k][i1][i2],f[k−1][i1][i2]+t)

第一条路径:从上至下;第二条路径:从左至右:
f [ k ] [ i 1 ] [ i 2 ] = m a x ( f [ k ] [ i 1 ] [ i 2 ] , f [ k − 1 ] [ i 1 ] [ i 2 − 1 ] + t ) f[k][i1][i2]=max(f[k][i1][i2], f[k-1][i1][i2-1]+t) f[k][i1][i2]=max(f[k][i1][i2],f[k−1][i1][i2−1]+t)

完整代码

cpp 复制代码
#include <iostream>
#include <algorithm>
using namespace std;
const int N=15;
int n;
int w[N][N];  //权重
int f[N*2][N][N];  //状态计算
int main(){
    scanf("%d",&n);
    int a,b,c;
    while(cin>>a>>b>>c,a||b||c) w[a][b]=c;
    for(int k=2;k<=n+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){  //j符合条件
                    int t=w[i1][j1];  //第一条路径
                    if(i1!=i2) t+=w[i2][j2];  //如果第二条路径与第一条路径重合,则权重w[i][j]不能重复增加
                    int &x=f[k][i1][i2];  //使用&简化代码
                    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]+t);  //第一条路径:来自左方;第二条路径:来自左方
                    x=max(x,f[k-1][i1][i2-1]+t);  //第一条路径:来自左方;第二条路径:来自上方
                }
            }
        }
    }
    printf("%d\n",f[n+n][n][n]);
    return 0;
}
相关推荐
火车驶向云外.113 小时前
计数排序算法
数据结构·算法·排序算法
Future_yzx6 小时前
算法基础学习——快排与归并(附带java模版)
学习·算法·排序算法
所以遗憾是什么呢?9 小时前
【题解】Codeforces Round 996 C.The Trail D.Scarecrow
数据结构·算法·贪心算法
被AI抢饭碗的人9 小时前
c++:vector
开发语言·c++
_zwy9 小时前
【Linux权限】—— 于虚拟殿堂,轻拨密钥启华章
linux·运维·c++·深度学习·神经网络
qystca9 小时前
【16届蓝桥杯寒假刷题营】第2期DAY4
数据结构·c++·算法·蓝桥杯·哈希
JNU freshman9 小时前
线段树 算法
算法·蓝桥杯
英国翰思教育10 小时前
留学毕业论文如何利用不同问题设计问卷
人工智能·深度学习·学习·算法·学习方法·论文笔记
人类群星闪耀时10 小时前
寻找两个正序数组的中位数:分治法与二分查找的结合
算法·leetcode
এ旧栎10 小时前
蓝桥与力扣刷题(240 搜索二维矩阵||)
算法·leetcode·矩阵·学习方法