列表

详情


DP24. 打家劫舍(二)

描述

你是一个经验丰富的小偷,准备偷沿湖的一排房间,每个房间都存有一定的现金,为了防止被发现,你不能偷相邻的两家,即,如果偷了第一家,就不能再偷第二家,如果偷了第二家,那么就不能偷第一家和第三家。沿湖的房间组成一个闭合的圆形,即第一个房间和最后一个房间视为相邻。
给定一个长度为n的整数数组nums,数组中的元素表示每个房间存有的现金数额,请你计算在不被发现的前提下最多的偷窃金额。

数据范围:数组长度满足 ,数组中每个值满足

输入描述

第一行输入一个正整数 n ,表示数组的长度。
第二行输入 n 个正整数,表示每个房间存有的现金。

输出描述

输出最多的偷窃金额

示例1

输入:

4
1 2 3 4

输出:

6

说明:

最优方案是偷第 2 4 个房间      

示例2

输入:

3
1 3 6

输出:

6

说明:

由于 1 和 3 是相邻的,因此最优方案是偷第 3 个房间      

原站题解

C++ 解法, 执行用时: 21ms, 内存消耗: 1176KB, 提交时间: 2022-03-16

#include <cstdio>
#include <vector>

int steal(std::vector<int> &nums, int st, int ed) {
    int post = 0, ppost = 0;
    int maxsum, ans = 0;
    for (int i = ed; i >= st; --i) {
        maxsum = std::max(post, nums[i] + ppost);
        ans = std::max(ans, maxsum);
        ppost = post;
        post = maxsum;
    }
    return ans;
}

int main() {
    int n;
    scanf("%d", &n);
    std::vector<int> nums(n);
    for (int i = 0; i < n; ++i) {
        scanf("%d", &nums[i]);
    }
    printf("%d\n", std::max(steal(nums, 0, n - 2), steal(nums, 1, n - 1)));
    return 0;
}

C++ 解法, 执行用时: 21ms, 内存消耗: 1220KB, 提交时间: 2022-04-12

#include <bits/stdc++.h>

using namespace std;

int robRange(vector<int>& nums, int start, int end) {
		int first = nums[start], second = max(nums[start], nums[start + 1]);
		for (int i = start + 2; i <= end; i++) {
			int temp = second;
			second = max(first + nums[i], second);
			first = temp;
		}
		return second;
	}

	int rob(vector<int>& nums) {
		int length = nums.size();
		if (length == 1) {
			return nums[0];
		} else if (length == 2) {
			return max(nums[0], nums[1]);
		}
		return max(robRange(nums, 0, length - 2), robRange(nums, 1, length - 1));
	}

int main() {
    ios::sync_with_stdio(false);
    int n;
    cin >> n;
    vector<int> v(n);
    for (int i = 0; i < n; ++i) {
        cin >> v[i];
    }
    cout << rob(v) << endl;
    return 0;
}

C++ 解法, 执行用时: 21ms, 内存消耗: 2060KB, 提交时间: 2022-07-22

#include <bits/stdc++.h>

using namespace std;


int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int n;
    cin >> n;
    int a[n];
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    if (n == 1) {
        cout << a[0] << endl;
    }
    else if (n == 2) {
        cout << (a[0] > a[1] ? a[0] : a[1]) << endl;
    }
    else if (n == 3) {
        int temp = (a[0] > a[1] ? a[0] : a[1]);
        temp = (temp > a[2] ? temp : a[2]);
        cout << temp << endl;
    }
    else {
        int v[n];
        v[0] = a[2];
        v[1] = (a[2] > a[3] ? a[2] : a[3]);
        for (int i = 2; i < n - 3; i++) {
            v[i] = max(v[i - 1], v[i - 2] + a[i + 2]);
        }
        int result = v[n - 4] + a[0];
        v[0] = a[1];
        v[1] = max(a[1], a[2]);
        for (int i = 2; i < n - 1; i++) {
            v[i] = max(v[i - 1], v[i - 2] + a[i + 1]);
        }
        result = max(result, v[n - 2]);
        cout << result << endl;
    }
}

C++ 解法, 执行用时: 23ms, 内存消耗: 2112KB, 提交时间: 2022-04-22

#include<iostream>
#include<cstring>
using namespace std;
const int MAXN = 2e5 + 5;
int n;
int arr[MAXN];
int dp[MAXN];
bool fg[MAXN];
int main() {
    scanf("%d", &n);
    for (int i = 0; i < n; ++i)
        scanf("%d", &arr[i]);
    int mmax = 0;
    dp[0] = arr[0], fg[0] = true;
    dp[1] = arr[1], fg[1] = false;
    dp[2] = dp[0] + arr[2], fg[2] = true;
    for(int i = 3; i < n; ++i){
        if(dp[i-2] > dp[i-3])
            dp[i] = dp[i-2], fg[i] = fg[i-2];
        else if(dp[i-2] < dp[i-3])
            dp[i] = dp[i-3], fg[i] = fg[i-3];
        else dp[i] = dp[i-2], fg[i] = fg[i-2] && fg[i-3];
        dp[i] += arr[i];
    }
    if(dp[n-1] > dp[n-2] && !fg[n-1])
        mmax = dp[n-1];
    else{
        mmax = dp[n-2];
        memset(dp, 0, sizeof(int) * n);
        dp[0] = 0;
        dp[1] = arr[1];
        dp[2] = arr[2];
        for(int i = 3; i < n; ++i){
            dp[i] = arr[i] + max(dp[i-2], dp[i-3]);
        }
        mmax = max(mmax, max(dp[n-1], dp[n-2]));
    }
        
    cout << mmax;

    return 0;
}

C++ 解法, 执行用时: 24ms, 内存消耗: 1160KB, 提交时间: 2022-07-21

#include <bits/stdc++.h> // C++万能头文件
using namespace std;
static const auto io_sync_off = [](){ // lambda表达式
    std::ios::sync_with_stdio(false); // 解除与scanf()等函数的同步
    std::cin.tie(nullptr); // 解除cin和cout的绑定
    return nullptr;
}();

/*
第一间房子和最后一间房子不能同时选
两次遍历,第一次求一定不选第一间房子的最大不相邻和
第二次求一定不选最后一间房子的最大不相邻和
两次较大值即为所求
*/
int main() {
    int n;
    cin >> n;
    int nums[n];
    int yes = 0, no = 0;
    cin >> nums[0];
    for (int i = 1; i < n; ++i) { // 一定不选第一间房子
        cin >> nums[i];
        int pre = no;
        no = max(no, yes);
        yes = pre + nums[i];
    }
    int res = max(yes, no);
    yes = no = 0;  // 重新计算一定不选最后一间的最大和
    for (int i = 0; i < n - 1; ++i) {
        int pre = no;
        no = max(no, yes);
        yes = pre + nums[i];
    }
    cout << max(res, max(yes, no)) << "\n";
    return 0;
}

上一题