动态规划(入门):各种数字三角形
一、一般的数字三角形:
给一个由数字形成的三角形,要求从三角形的顶端开始走,走到最后一行,要求走的路径之和最大。对于一般的数字三角行,可以正着走,也可以反着走。建议最好正走,不然加强版的数字三角形倒着走走不出来。
例题:
描述
示出了一个数字三角形。 请编一个程序计算从顶至底的某处的一条路
径,使该路径所经过的数字的总和最大。
每一步可沿左斜线向下或右斜线向下走;
1<三角形行数<25;
三角形中的数字为整数<1000;
输入格式
第一行为N,表示有N行
后面N行表示三角形每条路的路径权
输出格式
路径所经过的数字的总和最大的答案
测试样例1
输入
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
输出
30
正走代码:
#include<bits/stdc++.h> using namespace std; const int maxn = 25+5; int maps[maxn][maxn]; int main() { int n; while(~scanf("%d",&n)) { memset(maps,0,sizeof(maps)); for(int i=1;i<=n;i++)//从1开始并且初始化为0可以直接从(1,1)开始走 for(int j=1;j<=i;j++) { int now; scanf("%d",&now); maps[i][j] = max(maps[i-1][j],maps[i-1][j-1]) + now; } int ans = 0; for(int i=1;i<=n;i++) ans = max(maps[n][i],ans);//正走在最后需要找出各个路径走到最后一行时最大的一个数; printf("%d\n",ans); } }
反走代码:
#include<bits/stdc++.h> using namespace std; const int maxn = 25+5; int maps[maxn][maxn]; int main() { int n; while(~scanf("%d",&n)) { memset(maps,0,sizeof(maps)); for(int i=1;i<=n;i++) for(int j=1;j<=i;j++) scanf("%d",&maps[i][j]); for(int i=n-1;i>=0;i--) for(int j=1;j<=i;j++) maps[i][j] += max(maps[i+1][j],maps[i+1][j+1]); printf("%d\n",maps[1][1]);//反走的优势就在于此处,最大值直接就在(1,1)产生 } }
二、过定点的数字三角形(加强版一)
还是数字三角形,多了一个要求,就是需要走固定的一个点。这个题的想法很有意思,化一般为特殊,具体的做法就是将固定的点加上一个很大的数,在规划的过程中就一定会走过这个点,在输出的时候将这个很大的数减去就是正确答案。但是在加上一个很大的数的时候需要计算一下,不要加上一个很大的数的时候超范围了就很尴尬了。
例题:
描述
数字三角形必须经过某一个点,使之走的路程和最大
输入格式
第1行n,表示n行 <=25
第2到n+1行为每个的权值
第n+2行为两个数x,y表示必须经过的点
输出格式
最大值
测试样例1
输入
2
1
1 1
1 1
输出
2
数字三角形必须经过某一个点,使之走的路程和最大
输入格式
第1行n,表示n行 <=25
第2到n+1行为每个的权值
第n+2行为两个数x,y表示必须经过的点
输出格式
最大值
测试样例1
输入
2
1
1 1
1 1
输出
2
#include<bits/stdc++.h> using namespace std; const int maxn = 25 + 5; const int Max = 1e5; int maps[maxn][maxn]; int main() { int n; while(~scanf("%d",&n)) { memset(maps,0,sizeof(maps)); for(int i=1;i<=n;i++) for(int j=1;j<=i;j++) scanf("%d",&maps[i][j]); int x,y; scanf("%d%d",&x,&y); maps[x][y] += Max;//加上最大就一定会走过此点 for(int i=1;i<=n;i++) for(int j=1;j<=i;j++) maps[i][j] += max(maps[i-1][j],maps[i-1][j-1]); int ans = 0; for(int i=1;i<=n;i++) ans = max(ans,maps[n][i]); printf("%d\n",ans - Max);//最后输出的时候不要忘记减去Max } }
三、数字三角形mod100(加强版二)
这个题很能体现动态规划的思想,记录的主要是状态,下一个状态由前一个状态得到。
首先开一个三维数组,三位数组的前两维用来记录行和列,第三维大小开100,即0~99.用来记录状态(思考为什么是0~99)(其实第三维就是用来记录这个位置可能得到的所有的答案),看是否有这个数字,当这个数字存在的时候将第三维,也就是的这个数字记录的true(其实就是记录每次%100所得到的答案),下一个行就在上一行true的情况下转移。第【0】【0】【0】,【0】【1】【0】记录为true。这个题是将所有可能的得到的答案全部记录下来,最后遍历看最大的值。(嘴笨说不清楚)
例题:
描述
数字三角形
要求走到最后mod 100最大
输入格式
第1行n,表示n行 <=25
第2到n+1行为每个的权值
输出格式
mod 100最大值
测试样例1
输入
2
1
99 98
输出
99
数字三角形
要求走到最后mod 100最大
输入格式
第1行n,表示n行 <=25
第2到n+1行为每个的权值
输出格式
mod 100最大值
测试样例1
输入
2
1
99 98
输出
99
#include<bits/stdc++.h> using namespace std; const int Mod = 100; const int maxn = 25 + 5; int maps[maxn][maxn]; bool dp[maxn][maxn][100]; int main() { int n; while(~scanf("%d",&n)) { memset(maps,0,sizeof(maps)); memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++) for(int j=1;j<=i;j++) scanf("%d",&maps[i][j]); dp[0][0][0] = dp[0][1][0] = true;//这个初始化很重要 for(int i=1;i<=n;i++) for(int j=1;j<=i;j++) { for(int k=0;k<=99;k++) { int now; if(dp[i-1][j][k])//当上一个这个数值存在时就可以加上当前状态的值 { now = (maps[i][j] + k)%Mod; dp[i][j][now] = true; } if(dp[i-1][j-1][k]) { now = (maps[i][j] + k)%Mod; dp[i][j][now] = true; } } } int ans = 0; for(int i=1;i<=n;i++) for(int k=0;k<=99;k++) { if(dp[n][i][k]) { ans = max(ans,k); } } printf("%d\n",ans); } }
分类:
动态规划-简单DP
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库