(51nod)动态规划基础篇练习题

给定一个m行n列的矩阵,矩阵每个元素是一个正整数,你现在在左上角(第一行第一列),你需要走到右下角(第m行,第n列),每次只能朝右或者下走到相邻的位置,不能走出矩阵。走过的数的总和作为你的得分,求最大的得分。


输入

第1行:N,N为矩阵的大小。(2 <= N <= 500)
第2 - N + 1行:每行N个数,中间用空格隔开,对应格子中奖励的价值。(1 <= N[i] <= 10000)

输出

输出能够获得的最大价值。

输入示例

3
1 3 3
2 1 3
2 2 1

输出示例

11


分析:

假设我们定义f(int x,int y)表示从起点到第x行第y列的最优路径上的数之和,并假设这个矩阵事个二维数组A[][] (下标从1开始)

我们考虑一下,我们如何才能到(x,y)?前一步要么到(x – 1, y), 要么到(x, y – 1),因为有且只有这两个位置能到(x,y),那么怎样才能得到f(x,y)?按我们前面说的,如果从起点达到(x,y)的最优路径要经过(x – 1,y)或者(x,y – 1)则,从起点到达(x – 1,y)或者(x,y – 1)的路径一定也必须是最优的。

那么按照我们对f的定义,我们有从起点达到x,y的最优路径有两种可能:

要么f(x – 1, y) + A[x][y]
要么f(x, y – 1) + A[x][y]

我们要取最优,那自然取较大的

因此有f(x, y) = max(f(x – 1, y) , f(x, y – 1) ) + A[x][y]
这样原来要枚举指数条路径,现在对于每个位置只有两种情况啦。
有了递推关系还不够,有初值才能求解。

那我们看一下 f(1,1),显然这是在起点,没的选f(1,1) = A[1][1]。

那么按照递推式 f(1,2) = max(f(0, y) , f(1,1)) + A[1][2], 但是我们对f(0, y)没有定义呀!考虑下实际意义,这表示要么我们从上面到达(1,2)要么从左面到达(1,2),可是上面没有位置过来啊,这种说明没的选。所以我们可以定义f(0, y) = -∞, 同理我们也可以定义f(x, 0)  = -∞。

那么总结一下我们的递推式



分析一下这个算法的时间复杂度? 显然是O(m * n),空间复杂度也一样,因为我们打出了一张(m + 1) * (n + 1)的表格——因此空间也是O(m * n)的。

再走一步?


我们找到了最大的和,如何得到和最大的路径呢? 还是从递推式入手,我们发现如果f(x,y) = f(x – 1,y) + A[x][y] 则它是从上面过来的,所以前一个位置是(x – 1, y)
否则 f(x, y) = f(x, y – 1) + A[x][y]则它是从左面过来的,所以前一个位置是(x, y- 1)。

这看起来最优路径被唯一确定了? 不是的,事实上当f(x – 1,y) = f(x, y – 1)时,前一个位置在上面或者左面都可以——所以路径还是很多很多的!

代码实现:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[505][505];
int a[505][505];
int main()
{int n;
memset(dp,0,sizeof(dp));
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
int ans=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
	if(i!=0&&j!=0)
	dp[i][j]=max(dp[i][j-1],dp[i-1][j])+a[i][j];
	ans=max(dp[i][j],ans);
}
printf("%d",ans);
	return 0;
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值