Leetcode198.House Robber(线性DP),两种角度看状态

题意:

给出n个数,不能选取相邻的两个数,问怎么选取才能使和最大?

输入:
4
1 2 3 1
输出:
4
输入:
5
2 7 9 3 1
输出
12

a1,a2,a3…ai…an,假设选到前 i 个数,构成的答案集合的情况无非是 选了第 i 个,或是不选第 i 个两种情况。

方法一:

两种状态分开定义:f[i] 表示不选第 i 个数能达到的最大值, g[i] 表示选第 i 个数能达到的最大值。

  • 如果不选第 i 个数,计算f[i],则前 i 个的最大和可以转移到前 i-1 个数的最大和,而第 i-1 个数又可以包含选和不选,所以 f[i] = max (f [i -1] , g[i -1])。

  • 如果选第 i 个数,计算 g[i] , 那么第 i-1 个数一定不能选,所以 g[i] = f[i-1] + nums[i]。

  • 最后结果取 max(f[n],g[n])。(我这里输入的nums数组从 1 开始)

#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
const int inf =0x3f3f3f3f;
const int N=1e5+10;
int f[N],g[N];
int nums[N];
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
		scanf("%d",&nums[i]);//输入
	for(int i=1;i<=n;i++)
	{
		f[i]=max(f[i-1],g[i-1]);//不选第 i 个数 
		g[i]=f[i-1]+nums[i];//选第 i 个数
	}
	printf("%d\n",max(f[n],g[n]));
    return 0;
}
方法二:

把上述两种状态合起来定义 :dp[i] 表示到了第 i 个位置的最大和。其实就是先整合每个位置的 f[i] 和 g[i],方法一是分开计算两种状态,到最后合并取大值。

  • 如果选了第 i 个数 ,则第 i-1个数不嫩选,dp[i] = dp[i-2] + nums[i]。
  • 如果不选第 i 个数,则前 i 个数的最大和可以转移为前 i-1个数的最大和。
  • 状态转移方程: dp[i] = max(dp[i-2] + nums[i] , dp[i-1])。
#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
const int inf =0x3f3f3f3f;
const int N=1e5+10;
int dp[N],nums[N];
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
		scanf("%d",&nums[i]);
	dp[0]=0;//初始化 
	dp[1]=nums[1];
	for(int i=2;i<=n;i++)
		dp[i]=max(dp[i-2]+nums[i],dp[i-1]); 
	printf("%d\n",dp[n]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值