P1004方格取数

该博客介绍了一道编程题目,涉及到地图上的双路径行走问题。题目要求从左上角到右下角,路径只能向下和向右移动,并且在经过有数值的方格时获取该数值。由于需要走两次,简单的贪心策略无法得到最优解。博主通过分析问题的无后效性,使用动态规划方法来同时规划两条路径,以找到最大数值之和。代码中展示了如何初始化和更新动态规划数组以求解此问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意

给出一个地图,从左上角往右下角走两次,只能往下和右走,每次经过一个有值的点就会取走方格中的数(获得数且使当前方格变为0),求走两次最大的取得数之和。

解题思路

刚看到这题第一个想到的就是贪心,但是由于要走两次,所以无法保证两次的结果之和为最优,所以不能用贪心。
由于只能往右和下走,所以具有无后效性,因此可以用dp,只不过需要同时dp两条路。定义数组 f f f f i 1 , j 1 , i 2 , j 2 f_{i1},_{j1},_{i2},_{j2} fi1,j1,i2,j2表示当第一次走到i1,j1,第二次走到i2,j2时的最大值,因此上一步就有四种情况,只需枚举四种情况走到当前位置时取得的最大值即可。
由此可得:
f i 1 , j 1 , i 2 , j 2 = { 0                                                                                                           i 1 = 0   o r   j 1 = 0   o r   i 2 = 0   o r   j 2 = 0 m a x ( f i 1 − 1 , j 1 , i 2 − 1 , j 2 , f i 1 − 1 , j 1 , i 2 , j 2 − 1 , f i 1 , j 1 − 1 , i 2 − 1 , j 2 , f i 1 , j 1 − 1 , i 2 , j 2 − 1 ) + a i , j + a i 2 , j 2            i 1 ≠ i 2   o r   j 1 ≠ j 2 m a x ( f i 1 − 1 , j 1 , i 2 − 1 , j 2 , f i 1 − 1 , j 1 , i 2 , j 2 − 1 , f i 1 , j 1 − 1 , i 2 − 1 , j 2 , f i 1 , j 1 − 1 , i 2 , j 2 − 1 ) + a i , j                      i 1 = i 2   a n d   j 1 = j 2 f_{i1,j1,i2,j2}=\left\{\begin{matrix}0 \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ i1=0\ or\ j1=0\ or\ i2=0\ or\ j2=0 \\max(f_{i1-1,j1,i2-1,j2},f_{i1-1,j1,i2,j2-1},f_{i1,j1-1,i2-1,j2},f_{i1,j1-1,i2,j2-1})+a_{i,j}+a_{i2,j2}\ \ \ \ \ \ \ \ \ \ i1\ne i2\ or\ j1\ne j2 \\max(f_{i1-1,j1,i2-1,j2},f_{i1-1,j1,i2,j2-1},f_{i1,j1-1,i2-1,j2},f_{i1,j1-1,i2,j2-1})+a_{i,j}\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ i1=i2\ and\ j1=j2\end{matrix}\right. fi1,j1,i2,j2=0                                                                                                         i1=0 or j1=0 or i2=0 or j2=0max(fi11,j1,i21,j2,fi11,j1,i2,j21,fi1,j11,i21,j2,fi1,j11,i2,j21)+ai,j+ai2,j2          i1=i2 or j1=j2max(fi11,j1,i21,j2,fi11,j1,i2,j21,fi1,j11,i21,j2,fi1,j11,i2,j21)+ai,j                    i1=i2 and j1=j2
(感谢wtj提供的格式)

代码

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int n,m,f[15][15][15][15],a[100][100];
int main()
{
	cin>>n>>m;
	int x,y,z;
	while(1){
		cin>>x>>y>>z;
		a[x][y]=z;
		if(!x&&!y&&!z) break;for(int i1=1;i1<=n;i1++)
		for(int j1=1;j1<=n;j1++)//枚举第一条路位置
			for(int i2=1;i2<=n;i2++)
				for(int j2=1;j2<=n;j2++)//枚举第二条路位置
				{
					int p=max(f[i1-1][j1][i2-1][j2],max(f[i1-1][j1][i2][j2-1],max(f[i1][j1-1][i2-1][j2],f[i1][j1-1][i2][j2-1])));//上一步所取得的最大值
					if(i1==i2&&j1==j2) f[i1][j1][i2][j2]=p+a[i2][j2];
					else f[i1][j1][i2][j2]=p+a[i1][j1]+a[i2][j2];//如果走到了同一个位置就只加一个
				}
	cout<<f[n][n][n][n];
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值