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 
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 
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;
}

你可能感兴趣的:(#,DP)