<LeetCode OJ> (198 / 213) House Robber(I / II)

You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, 

the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and

 it will automatically contact the police if two adjacent houses were broken into on the same night.

Given a list of non-negative integers representing the amount of money of each house, 

determine the maximum amount of money you can rob tonight without alerting the police.


分析:

首先理清思路:
最值方案问题,考虑采用动态规划
定义子问题:令maxV[i]表示盗贼从第1家到达第i家能偷到的最大money数;

显然对于每一栋房子,只能做两种选择----偷或者不偷,

1),如果不偷,显然,还是上一次的最大利润数maxV[i-1]

2),如果偷,那么nums[i]的利润已经获得。但是这里因为第i-1次存在不偷或者偷的情况,所以又分两种情况

A),如果i-1次不偷,显然maxV[i-1]=maxV[i-2],可知maxV[i]=maxV[i-2]+nums[i]

B),如果i-1次偷,显然为了能产生maxV[i]的最大值就不能来自子问题maxV[i-1],即maxV[i-2]是安全的最大值来源,可知即使偷,答案还是maxV[i]=maxV[i-2]+nums[i]
所以当到达第i家的时候,i>=2,此时能够得到的钱数应该为maxV[i]=max{maxV[i-1],maxV[i-2]+nums[i]},

时间复杂度O(N),空间复杂度O(N)

class Solution {
public:
    int rob(vector<int>& nums) {
        if(nums.size() == 0)
             return 0;
        vector<int> maxV(nums.size());
        maxV[0] = nums[0];
        maxV[1] = max(nums[0], nums[1]);
        for(int i = 2; i < nums.size(); i ++)
            maxV[i] = max(maxV[i-2]+nums[i], maxV[i-1]);
        return maxV[nums.size()-1];
    }
};


学习讨论区的优化,另一种形式:

实际上我们并不需要申请一个数组来获取答案,从上面的看得出,我们只需要前一次偷获取的最大利润,和前一次未偷获取的最大利润即可。
Since we are not allowed to rob two adjacent houses, we keep two variables pre and cur. During the i-th loop, pre records the maximum profit that we do not rob the i - 1-th house and thus the current house (the i-th house) can be robbed while cur records the profit that we have robbed the i - 1-th house.
The code is as follows.

空间复杂度降为1,时间复杂度还是一样的:

class Solution {
public: 
    int rob(vector<int>& nums) {
        int  pre = 0, cur = 0;
        for (int i = 0; i < nums.size(); i++) {
            int temp = max(pre + nums[i], cur);
            pre = cur;//没有偷i-1栋房子的最大利润
            cur = temp;//偷了i-1栋房子的最大利润
        }
        return cur;
    }
};





Note: This is an extension of House Robber.

After robbing those houses on that street, the thief has found himself a new place for his thievery so that he will not get too much attention. This time, all houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, the security system for these houses remain the same as for those in the previous street.

Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.



没思路,没理解题意:不理解这个数组怎么体现循环呢?
别人的算法(参考讨论区)
因为第一个和最后一个不能同时偷
创建两个独立的数组,其中一个包括第一个不包括最后一个,另一个包括最后一个但不包括第一个
分别利用House Robber的算法,两者的较大值就是最优值

class Solution {
public:
    int robOriginal(vector<int>& nums) {
        if(nums.size() == 0)
             return 0;
        vector<int> maxV(nums.size());
        maxV[0] = nums[0];
        maxV[1] = max(nums[0], nums[1]);
        for(int i = 2; i < nums.size(); i ++)
            maxV[i] = max(maxV[i-2]+nums[i], maxV[i-1]);
        return maxV[nums.size()-1];
    }
    
    int rob(vector<int>& nums) {
        if(nums.empty()) 
            return 0;
        if(nums.size() == 1) 
            return nums[0];

        vector<int> numsA(nums.begin() + 1, nums.end());
        vector<int> numsB(nums.begin(), nums.end()-1);

        return max(robOriginal(numsA), robOriginal(numsB));
    }
};



九度女生排座位

本题连动九度女生排座位问题,上面的问题也可以考虑下面的形式来解:

题目描述:

计算机学院的男生和女生共n个人要坐成一排玩游戏,因为计算机的女生都非常害羞,男生又很主动,所以活动的组织者要求在任何时候,一个女生的左边或者右边至少有一个女生,即每个女生均不会只与男生相邻。现在活动的组织者想知道,共有多少种可选的座位方案。


例如当n为4时,共有
女女女女, 女女女男, 男女女女, 女女男男, 男女女男, 男男女女, 男男男男
7种。

输入:

输入包含多组测试用例,每组测试用例仅包含一个整数n(1<=n<=1000)。

输出:

对于每组测试用例,输出一个数代表可选的方案数,为防止答案过大,答案对1000000007取模。

样例输入:
1
2
4
样例输出:
1
2
7
#include "vector"  
#include "string"  
#include "algorithm"  
#include <iostream>  
#include "stack"  
#include <cmath>  
#include <set>  
  
using namespace std;  
  
//最值方案问题,考虑采用动态规划  
//令dp[i][0]表示共i个人的座位方式,且最后一个是男生,dp[i][1]则是女生  
//无论什么时候最后一个人要么是男要么是女  
//如果最后一个是男生,显然dp[i][0] = dp[i - 1][0] + dp[i - 1][1];  
//因为前面的女生已经满足座位关系,再加一个男生一样满足座位关系  
//如果最后一个是女生,显然它的前一个不能是男生,那么只能是女生,  
//此时方式数目就是dp[i-1][1]  
//但是dp[i-1][1]中并没包括倒数第二女生前面可以是男生的情况(因为最后一个也是女生,所以此时是可以的),此时数目是dp[i-2][0]  
const int maxx = 1001;  
const int MOD = 1000000007;  
long  dp[maxx][2];  
void init()  
{  
    long sum = 0;  
  
    dp[1][0] = 1;//男生  
    dp[1][1] = 0;//女生  
  
    dp[2][0] = 1;//男生  
    dp[2][1] = 1;//女生  
    for (int i = 3; i<1001; ++i)  
    {  
        //男生  
        dp[i][0] = dp[i - 1][0] + dp[i - 1][1];  
        dp[i][0] %= MOD;  
        //女生  
        dp[i][1] = dp[i - 2][0] + dp[i - 1][1];  
        dp[i][1] %= MOD;  
    }  
}  
  
int main(){  
    long  n, ans;  
  
    init();  
  
    while (cin>>n)  
    {  
        ans = (dp[n][0] + dp[n][1]) % MOD;  
        cout << ans << endl;  
    }  
    return 0;  
}  



注:本博文为EbowTang原创,后续可能继续更新本文。如果转载,请务必复制本条信息!

原文地址:http://blog.csdn.net/ebowtang/article/details/50353867

原作者博客:http://blog.csdn.net/ebowtang


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值