动态规划/贪心总结(一)

39 篇文章 4 订阅
30 篇文章 0 订阅
这篇博客探讨了动态规划在解决最长递增子序列和跳跃游戏问题上的应用。首先介绍了如何使用动态规划求解一维数组中的最长递增子序列,接着解释了二维数组情况下,如信封嵌套问题的解决方案。同时,讨论了最大子数组问题的处理方法。对于跳跃游戏I和II,提出了判断可达性和最小跳跃次数的贪心策略。最后,简要提到了01背包问题的状态转移方程及其优化。这些例子展示了动态规划和贪心策略在解决复杂问题中的高效性。
摘要由CSDN通过智能技术生成

最长递增子序列(一维)

子序列是可以不连续的。
dp[i]是i位置以num[i]结尾的最长子序列长度
状态转移方程:

d p [ i ] = m a x ( d p [ i ] , d p [ j ] + 1 ) , j < i 且 满 足 n u m [ i ] > n u m [ j ] dp[i] = max(dp[i],dp[j]+1) ,j<i且满足num[i]>num[j] dp[i]=max(dp[i],dp[j]+1),j<inum[i]>num[j]

代码:

memset(dp,1,sizeof(dp)) //初始化为1,因为自己本身。
for(int i=0;i<n;++i)
	for(int j=0;j<i;++j)
	{
		if(nums[i]>nums[j])
			dp[i] = max(dp[i] ,dp[j]+1);
	}

之后遍历一篇dp取最大的值就可以了。

最长递增子序列(二维)

一般题目是一个二维的数据,如给信封的长和宽,问最多可以嵌套多少个信封。
思路:
可以统一将信封的长进行升序排列,如果长度一样,就以宽度降序排列。
然后将宽度取出,在宽度中最长递增子序列就是答案。

bool cmp(vector<int>a,vector<int>b)
{
	a[0] == b[0]?return a[1]>b[1]:a[0]<b[0] ;
}

sort(nums,nums+n,cmp)
vector<int>ans;
for(int i =0;i<n;++i)
	ans.push_back(nums[i][1]);
//然后将这个ans求最长递增子序列。

最大子数组

子数组或子字符串是连续的。
dp[i]是i位置以num[i]结尾的最大数组和
在dp[i]位置只有两个选择,一个是与前一个数组合并,另一个是自己新建立一个数组。
所以有状态转移方程:
d p [ i ] = m a x ( d p [ i − 1 ] + n u m s [ i ] , n u m s [ i ] ) dp[i]=max(dp[i-1]+nums[i],nums[i]) dp[i]=max(dp[i1]+nums[i],nums[i])

dp[0] = nums[0];//因为第一个数字只能选择自己。
for(int i =1;i<n;++i)
	dp[i]=max(dp[i-1]+nums[i],nums[i]) ;
//然后遍历一边dp数组,取最大值就是答案了。

跳跃游戏I

题意是:给一个数组nums,nums[i]是在位置i最多能向前跳跃的步数。问能否可以跳跃到最后一个位置。

思路:我们记录在位置i能最多跳跃到的位置,将问题转化为这最大的位置是否比最后一个位置大就好了。

int ans = 0;
for(int i=0;i<n-1;++i)
{
	ans = max(ans,i+nums[i]);
	if(ans<=i) //说明遇到了0,那么就无法跳了。
		return false;
	return ans>=n-1;
}

跳跃游戏II

现在问的是跳到最后一个需要的最少跳跃次数。

贪心思路:我们在一个位置上最长能跳跃到的区间上,选出最大的一个跳跃步数就可以。

int end = 0; //站在索引i,最大能跳跃到end
int fartest =0; //从索引[i...end]起跳,最远到的距离。
int jump = 0;
for(int i =0;i<n-1;++i)
{
	fartest = max(fartest,i+nums[i]);
	if(end = i)
	{
		jump ++;
		end = fartest ;
	}
}

01背包

01背包的状态转移方程为
f [ i ] [ j ] = m a x ( f [ i − 1 ] [ j ] , f [ i − 1 ] [ j − w [ i ] ] + v [ j ] ) f[i][j] = max(f[i - 1][j], f[i - 1][j - w[i]] + v[j]) f[i][j]=max(f[i1][j],f[i1][jw[i]]+v[j])

i代表对i件物体做决策,有两种方式—放入背包和不放入背包。
j表示当前背包的容量。

不放入背包时:第i次决策后的最大价值和第i-1次决策时候的价值是一样的(还是原来的那些物体,没多没少)。
放入背包时:第i次决策后的价值为 第i-1次决策时候的价值 加上 当前物体的价值v[j]。物体放入背包后会使背包容量变为 j ,即没放物体之前背包的容量为j - w[i]。想想啊当前背包容量为j,而这个j是在加了w[i]之后得到的,那么i-1时候背包容量不就是j-w[i]嘛

//代码里面将整个f初始化为0
for (int i = 1; i <= n; i++)
{
	for (int j = V; j >= 0; j--)
	{
		if (j >= w[i])//如果背包装得下当前的物体
		{
			f[i][j] = max(f[i - 1][j], f[i - 1][j - w[i]] + v[i]);
		}
		else//如果背包装不下当前物体
		{
			f[i][j] = f[i - 1][j];
		}
	}
}

优化,只需要一维数组就好了

//代码里面将整个f初始化为0
for (int i = 1; i <= n; i++)
{
	for (int j = V; j >= w[i]; j--)
	{
		f[j] = max(f[j], f[j - w[i]] + v[i]);
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

落春只在无意间

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

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

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

打赏作者

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

抵扣说明:

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

余额充值