动态规划(简单习题)

本文讨论了如何使用动态规划和两种不同的方法(从下而上的二维数组法和自上而下的DFS法)解决数字三角形中的最大值问题。作者还提到了01背包和完全背包的区别,并给出了相应的代码示例。
摘要由CSDN通过智能技术生成

数字三角形 Number Triangles


首先我看到这个题目就在思考应该用怎样一个数据结构来存放这些数据,是二叉树,还是并查集那样的连接。
第二个问题这个使用动态规划应该怎样构建状态转移方程,使用dfs来遍历然后使用一个数组来存放最大价值吗? 

针对第一个问题我们竟然要使用一个二维数组来存放(是我想复杂了,直接用二维数组来存就好了,应为下一层判断大打谁小然后再直接放进去就可以了)

思路一:从下而上

从倒数第二层开始,将每个下一层相邻的两个数分别与这个数进行相加,然后使用max函数判断那个大,那个大这个数就存下这个数 其状态转移方程就是dp[i][j]+=max(dp[i+1][j],dp[i+1][j+1]);(需要注意的是我的这个是自加,第一次写就是没有自加导致的错误)

这个思路值得学习的地方就是:第一使用了二维数组进行存放了数据,第二就是从下而上。

代码如下:

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1000+10;
int dp[N][N];
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=i;j++)
		{
			cin>>dp[i][j];
		}
	}
	for(int i=n-1;i>=1;i--)
	{
		for(int j=1;j<=i;j++)
		{
			dp[i][j]+=max(dp[i+1][j],dp[i+1][j+1]);//这里是自加
		}
	}
	cout<<dp[1][1]<<endl;//那么最后开头的数就是最大的数
	
	return 0;
}

思路二:使用dfs(虽然这个时间会爆,但是可以复习一下dfs)自上而下

我看题解定义的dfs函数都是使用int类型来定义的,但是由于我写dfs函数的时候常常用void类型,所以我就是使用void类型来写一个dfs函数的思路吧。

首先就是考虑使用那种数据结构来存放数据,这里还是使用一个二维数组来存放数据,这个dfs函数终止条件就是当检查到最后一层的就可以停止了,但是实际上是要比最后一层,多一层但是说句实话我现在一般这种退出条件都是试出来的,我具体也不知道是怎么得出来的。

其实这里是不需要一个检查是否已经走过的检查数组,因为方向都是向下的,不会出现返祖现象,所以可以不需要vis数组,节省空间

代码如下:

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1000+10;
int dp[N][N];
//int vis[N][N];
int maxN=-1;
int n;
void dfs(int x,int y,int sum)
{
	if(x>=n+1)
	{
		maxN=max(maxN,sum);
		return ;
	}
//	if(vis[x][y]==1)
//	return ;
//	vis[x][y]=1;
	dfs(x+1,y,sum+dp[x][y]);
	dfs(x+1,y+1,sum+dp[x][y]);
//	vis[x][y]=0;
	return ;
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=i;j++)
		{
			cin>>dp[i][j];
		}
	}
	dfs(1,1,0);
	cout<<maxN<<endl;
	return 0;
}

疯狂的采药

 这是一个非常典型的完全背包问题,好了那么问题就来了,01背包和完全背包的区别是什么?
01背包对所有物品只能取一次,而完全背包所有物品可以取无限次。那么怎么体现这个区别呢?
01背包每次取最优解都是在上行中,所以在状态转移方程中取最优时是dp[j],而在01背包中是dp[j-1],这个就是完全背包和01背包的区别。
  关于背包问题还有值得注意的是最后的取值是下标为背包容量最大的时候。

代码如下

#include<iostream>
#include<algorithm>
using namespace std;
const int N=100000;
const int M=1e7+10;
unsigned long long dp[M];
unsigned long long w[N];
unsigned long long v[N];
unsigned long long sum=0,n;
int main()
{
	cin>>sum>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>w[i]>>v[i];
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=w[i];j<=sum;j++)
		{
			dp[j]=max(dp[j],dp[j-w[i]]+v[i]);//如果是01背包问题那么就是max(dp[j-1],dp[j-w[i]]+v[i])
		}
	}
	cout<<dp[sum];//无论是01背包还是完全背包 最后的答案都是取容量最大的时候
	return 0;
}

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白色的风扇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值