描述
你是一个经验丰富的小偷,准备偷沿湖的一排房间,每个房间都存有一定的现金,为了防止被发现,你不能偷相邻的两家,即,如果偷了第一家,就不能再偷第二家,如果偷了第二家,那么就不能偷第一家和第三家。沿湖的房间组成一个闭合的圆形,即第一个房间和最后一个房间视为相邻。
给定一个长度为n的整数数组nums,数组中的元素表示每个房间存有的现金数额,请你计算在不被发现的前提下最多的偷窃金额。
数据范围:数组长度满足 1≤n≤2×10^5 1≤nums[i]<=5000
输入描述:
第一行输入一个正整数 n ,表示数组的长度。
第二行输入 n 个正整数,表示每个房间存有的现金。
输出描述:
输出最多的偷窃金额
示例1
输入:
4 1 2 3 4
输出:
6
说明:
最优方案是偷第 2 4 个房间
示例2
输入:
3 1 3 6
输出:
6
说明:
由于 1 和 3 是相邻的,因此最优方案是偷第 3 个房间
这是一道经典的动态规划问题,可以使用 dp 数组记录偷到第 i 个房间时的最大金额,状态转移方程为:
//如果我们去偷了第i个房间,那么第i-1号房间就不能偷,如果我们不去第i号房间,那么我们可以去//i-1号房间。得出
dp[i] = max(dp[i-2]+nums[i], dp[i-1])
由于我们去偷了一号就不能去偷最后一号,所以可以分为两种情况,第一种是偷1号房间,一种是偷最后的房间而不去第一个房间。设dp为不偷一号房间,dp2为不偷最后的房间。
#include <stdio.h>
long long int max(long long int a,long long int b){
return a>b ? a :b;
}
long long int my_(long long int *a,long long int n){
int dp1[200001],dp2[200001];
dp1[0]=0;dp1[1]=0; //保证不偷一号房间
dp2[0]=0;dp2[1]=a[1]; //此时的一号房间有钱,可以去偷嘿嘿。
//不偷第一个
for(long long int i=2;i<=n;i++){
dp1[i]=a[i];
dp1[i]=max(dp1[i-2]+dp1[i],dp1[i-1]);
}
//不偷最后一个
for(long long int i=2;i<=n-1;i++){
dp2[i]=a[i];
dp2[i]=max(dp2[i-2]+dp2[i],dp2[i-1]);
}
long long int last=max(dp1[n],dp2[n-1]); //找到这两种情况偷的最多的钱的情况
return last;
}
int main() {
long long int n,i,a[200001];
scanf("%lld",&n);
for(i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
long long int test=my_(a,n);
printf("%lld",test);
}
其中,dp2[]表示可以偷第1 个房间而不偷最后一个房间,dp1[] 表示不偷第 i 个房间而可以偷最后一个。由于是一个闭合的圆形,所以需要分别计算不偷第一个房间和不偷最后一个房间的情况,最终结果取两种情况的最大值。