打家劫舍2

描述

你是一个经验丰富的小偷,准备偷沿湖的一排房间,每个房间都存有一定的现金,为了防止被发现,你不能偷相邻的两家,即,如果偷了第一家,就不能再偷第二家,如果偷了第二家,那么就不能偷第一家和第三家。沿湖的房间组成一个闭合的圆形,即第一个房间和最后一个房间视为相邻。

给定一个长度为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 个房间而可以偷最后一个。由于是一个闭合的圆形,所以需要分别计算不偷第一个房间和不偷最后一个房间的情况,最终结果取两种情况的最大值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值