This is the second version of House Robber.
题目描述:
You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed. All houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, adjacent houses have a security system connected, and it will automatically contact the police if two adjacent houses were broken into on the same night.
Given an integer array nums representing the amount of money of each house, return the maximum amount of money you can rob tonight without alerting the police.
样例输入:
输入一个整数n,表示这条街上房子的总数,接下来一行输入n个数mi,表示各房子中存储的金钱。
输出:
一个数,表示你可以偷取的最大价值。
样例输入:
3
1 2 3
样例输出:
3
提示:
1<=n<=100
0<=mi<=1000
这题不是最原始的打家劫舍,那个太简单了。这个是这一条街成了一个环,也就是说,如果偷了第一个房子里的钱,那就不能偷最后一个房子里的钱;如果偷了最后一个房子里的钱,就不能偷第一个房子里的钱。
那怎么办呢?一开始我想搞个flag标记,记录一下有没有偷第一个房子里的钱,但是搞了一会儿发现这样很难做出来,遂放弃。后来看了题解,恍然大悟!其实根本不用那么麻烦。
根据打家劫舍第一个版本,如果只有一间房子,我们肯定会偷,那么就是dp[0]=nums[0].如果有两家房子,那么dp[1]=max(nums[0],nums[1]).这两个初始条件的值放到这道题里仍然成立。好,现在我们来看看三间或三间以上房子的情况。如果是第一个版本,dp[i]表示的是到i这个位置截止共偷了多少钱,那么,到i这个位置,一定要么是从i-2来的,要么是从i-1来的,我们只需要取最大值就行了。所以dp[i]=max(dp[i-2]+nums[i],dp[i-1]).
现在放到这道题里面,第一个房子和第二个房子是相邻的,所以我们的动态规划方程有什么变化吗?没有。变的是偷取钱财的房子的范围。
如果我们偷第一间屋,那最后一间屋肯定就不能偷,此刻偷的范围就是从第一间房子到倒数第二间房子;如果偷的是最后一间屋子,那么偷的范围就是从第二件房子到最后一间房子。最后,我们只需要返回这二者的较大值就可以了。
为了卷死大多数人,决定不使用dp数组,太浪费内存了[狗头保命]。我们使用两个值来存,这期间不断更新就行。
下面是C++代码:
1 #include <cstdio> 2 #include <algorithm> 3 #define N 1005 4 using namespace std; 5 int nums[N]; 6 int n; 7 int range(int start, int end, int nums[]) 8 { 9 int pre = nums[start]; 10 int cur = nums[start + 1]; 11 for (int i = start + 2; i < end; ++i) { 12 int next = max(pre + nums[i], cur); 13 pre = cur; 14 cur = next; 15 } 16 return max(cur, pre); 17 } 18 int rob(int nums[]) 19 { 20 if (n == 1) { 21 return nums[0]; 22 } 23 else if (n == 2) { 24 return max(nums[0], nums[1]); 25 } 26 return max(range(0, n - 1, nums), range(1, n, nums)); 27 } 28 int main() 29 { 30 scanf_s("%d", &n); 31 for (int i = 0; i < n; ++i) { 32 scanf_s("%d", &nums[i]); 33 } 34 int ans = rob(nums); 35 printf("%d\n", ans); 36 return 0; 37 }
至于range函数为什么要返回pre和cur的最大值,额。。。这是我实践出来的结果,我也不知道为什么,反正你只返回一个肯定会出错,既然这样,那就返回二者较大的那个吧。