数字三角形模型
数字三角形模型
以数字三角形
这个题为原型的所有题型。
AcWing 898.数字三角形
原题链接:https://www.acwing.com/problem/content/900/
解题思路
将这个数字三角形看成一个矩阵,然后DP分析
代码
#include<iostream>
#include<cstring>
using namespace std;
const int N = 510;
const int INF = 1e9;
int f[N][N],a[N][N];
int n;
int main()
{
scanf("%d",&n);
for(int i = 0; i <= n; i++)
for(int j = 1; j <= i;j ++)
scanf("%d",&a[i][j]);
// 因为存在负数,所以两边也要初始化为负无穷
for(int i = 0; i <= n; i ++)
for(int j = 0; j <= i + 1; j ++)
f[i][j] = -INF;
f[1][1] = a[1][1];
for(int i = 2; i <= n; i ++)
for(int j = 1; j <= i; j ++)
f[i][j] = a[i][j] + max(f[i-1][j-1],f[i-1][j]);
int res = -INF;
for(int j = 1; j <= n; j ++) res = max(res,f[n][j]);
printf("%d",res);
return 0;
}
AcWing 1015. 摘花生
原题链接:https://www.acwing.com/problem/content/1017/
思路
代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 110;
int t;
int f[N][N],w[N][N];
int r,c;
int main()
{
cin >> t;
while(t --)
{
cin >> r >> c;
for(int i = 1; i <= r; i ++)
for(int j = 1; j <= c; j ++)
cin >> w[i][j];
memset(f,0,sizeof f);
for(int i = 1; i <= r; i ++)
{
for(int j = 1; j <= c; j ++)
{
f[i][j] = w[i][j] + max(f[i-1][j],f[i][j-1]);
}
}
cout << f[r][c] << endl;
}
return 0;
}
AcWing 1018. 最低通行费
原题链接:https://www.acwing.com/problem/content/1020/
思路
阅读理解:左上角到右下角,时间不超过2n-1,说明只能向下或者向右走,不能回头 => 摘花生问题
边界处理时,第一行和第一列只能从一遍过来,不能从外面过来(外面的值都是正无穷)
代码
#include<iostream>
#include<cstring>
using namespace std;
const int N = 110;
int n,f[N][N],w[N][N];
int main()
{
cin >> n;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++)
cin >> w[i][j];
memset(f,0x3f,sizeof f);
for(int i = 1; i <= n; i ++)
{
for(int j = 1;j <= n; j ++)
{
if(i == 1 && j == 1) f[1][1] = w[1][1];
else f[i][j] = w[i][j] + min(f[i-1][j],f[i][j-1]);
}
}
cout << f[n][n];
return 0;
}
AcWing 1027. 方格取数
原题链接:https://www.acwing.com/problem/content/1029/
思路
虽然以摘花生为原型,但是不可以分两次摘花生
。
先看一个例子,
比如:
0 1 0
2 2 2
1 0 0
如果分两次,第一次最优肯定是把三个2取到然后结束,第二次就只能取一个1。
如果同时来,那么是可以把所有的数都取下的。
因为第一次摘花生
,第一次的最优解已经影响到第二次的最优解了。两次分开走并不是全局最优的。只能dp同时走才可以找到全局最优方案。
所以我们只能同时行进去找最优解。(相当于让两个人同时走)
对于重复计算,只有两个人走到同一个格子的时候就会重复。
两个人走的步数一样的时候,有可能走到同一个格子 => i1+j1 == i2+j2 可能重复计算
同时走状态表示就是f[i1,j1,i2,j2],如果同时走到一个格子,肯定i1+j1 == i2+j2, 两个人同时走,走的步数总是一样的,令k = i1+j2 = i2+j2,可以优化掉一维。
代码
#include<iostream>
#include<cstring>
using namespace std;
const int N = 15;
int f[N*2][N][N],w[N][N];
int 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 <= n + n; k ++) // 从[1,1]开始走
{
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 t = w[i1][j1];
if(i1 != i2) t += w[i2][j2];
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);
}
}
}
}
cout << f[n+n][n][n];
return 0;
}
AcWing 275. 传纸条
原题链接:https://www.acwing.com/problem/content/277/
思路
大致思路和 方格取数 这一题相同
需要注意的是,本题是n×m的矩阵。
k 的取值是: k <= n + m
x1,x2的范围应该是:1 <= x <= n
y1,y2的范围应该是:1 <= y <= m
y1 = k - x1
1 <= k - x1 <= m
所以 x1 <= k - 1 , x1 >= k - m
即 max(1,k-m) <= x1 <= min(n,k-1)
最后的答案是f[n+m][n][n]
:f[n+m][n][n]代表第一次从(1,1)走到(n,k-n),第二次从(1,1)走到(n,k-n)
代码
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 55;
int f[N+N][N][N],w[N][N],n,m;
int main()
{
cin >> n >> m;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
cin >> w[i][j];
for(int k = 2; k <= n + m; k ++) // 从[1,1]开始走,防止数组越界
{
for(int i1 = max(1,k-m); i1 <= min(n,k-1); i1 ++)
{
for(int i2 = max(1,k-m); i2 <= min(n,k-1); i2 ++)
{
int j1 = k - i1,j2 = k - i2;
int t = w[i1][j1];
if(i1 != i2) t += w[i2][j2];
// 四种情况,可以用个小循环枚举出
for(int a = 0; a <= 1; a ++)
for(int b = 0; b <= 1; b ++)
f[k][i1][i2] = max(f[k][i1][i2],f[k-1][i1 - a][i2 - b] + t);
}
}
}
cout << f[n+m][n][n] ; // f[n+m][n][n]代表第一次从(1,1)走到(n,k-n),第二次从(1,1)走到(n,k-n)
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!