dp学习之BadNeighbors解法
2016-04-04 11:53
543 查看
这是来自Topcoder的一道动态规划有关的题目,原文如下
The old song declares “Go ahead and hate your neighbor”, and the residents of Onetinville have taken those words to heart. Every resident hates his next-door neighbors on both sides. Nobody is willing to live farther away from the town’s well than his neighbors, so the town has been arranged in a big circle around the well. Unfortunately, the town’s well is in disrepair and needs to be restored. You have been hired to collect donations for the Save Our Well fund.
Each of the town’s residents is willing to donate a certain amount, as specified in the int[] donations, which is listed in clockwise order around the well. However, nobody is willing to contribute to a fund to which his neighbor has also contributed. Next-door neighbors are always listed consecutively in donations, except that the first and last entries in donations are also for next-door neighbors. You must calculate and return the maximum amount of donations that can be collected.
题目大意就是:有一组首尾相连的数组,要求在不选取相邻的数据的前提下,挑选其中的数据使其和最大。
如:{10,3, 2, 5, 7, 8}
结果:19
分析:这组数据有如下可选取的可能10+2+7或3+5+8显然10+2+7更大(注意:因为是首尾相连所以第一个元素和最后一个也是相邻数据)
{11, 15}
结果:15
问题分析求解:
假设数据为x0,x2,…..,xn-1,并且这组数据首尾无关(为降低问题复杂度),用数组dp
存储在计算过程中包含xi的子问题的最大值。
由于使用动态规划的两要素是:最优子结构和子问题重叠,所以先来刻画一个最优子结构。很容易知道当i=0时,dp[0] = x0, 当i>0时,由于不能选取相邻元素所以i - 1不在考虑范围,所以有两种选择一种选dp[j](其中j < i - 1)中最大的和xi相加,还有就是只要xi,因为j < i-1,所以不会有相邻元素包含在dp[i]中因此必然符合条件。
状态转移方程:
dp[i] = x0; 其中( i = 0 )
dp[i] = max(xi, dp[j] + xi)其中(j < i - 1);
最大值为val = max(dp[0],….,dp
);
但上述求解过程是在数据首尾不相连的情况下进行的,可题目条件是首尾相连。此时我们可以将原问题分解为两个子问题分别求解,然后选取他们解的最大值。假设数据为a0,…,an,则可将问题分解为a0,….,an-1(要首不要尾),a1,…..an(要尾不要首)
程序源码(c++):
参考文章原文来自http://apps.topcoder.com/forums//?module=Thread&threadID=757580&start=0&mc=10重点内容
Hi. I think you’ve already solved this problem, but this will help whoever is learining dp. (as me)
Let’s supose we have an array ‘donations’ which is the amount of money form the person i
Let’s think a little bit and define the following
Let dp[i] be the maximum amount of money USING THE PERSON i and using zero or more persons less than i-1
It follows that
dp[0] = donations[0] (base case)
Then
dp[i] = max( donations[i] , dp[j] + donations[i] for every j
The old song declares “Go ahead and hate your neighbor”, and the residents of Onetinville have taken those words to heart. Every resident hates his next-door neighbors on both sides. Nobody is willing to live farther away from the town’s well than his neighbors, so the town has been arranged in a big circle around the well. Unfortunately, the town’s well is in disrepair and needs to be restored. You have been hired to collect donations for the Save Our Well fund.
Each of the town’s residents is willing to donate a certain amount, as specified in the int[] donations, which is listed in clockwise order around the well. However, nobody is willing to contribute to a fund to which his neighbor has also contributed. Next-door neighbors are always listed consecutively in donations, except that the first and last entries in donations are also for next-door neighbors. You must calculate and return the maximum amount of donations that can be collected.
题目大意就是:有一组首尾相连的数组,要求在不选取相邻的数据的前提下,挑选其中的数据使其和最大。
如:{10,3, 2, 5, 7, 8}
结果:19
分析:这组数据有如下可选取的可能10+2+7或3+5+8显然10+2+7更大(注意:因为是首尾相连所以第一个元素和最后一个也是相邻数据)
{11, 15}
结果:15
问题分析求解:
假设数据为x0,x2,…..,xn-1,并且这组数据首尾无关(为降低问题复杂度),用数组dp
存储在计算过程中包含xi的子问题的最大值。
由于使用动态规划的两要素是:最优子结构和子问题重叠,所以先来刻画一个最优子结构。很容易知道当i=0时,dp[0] = x0, 当i>0时,由于不能选取相邻元素所以i - 1不在考虑范围,所以有两种选择一种选dp[j](其中j < i - 1)中最大的和xi相加,还有就是只要xi,因为j < i-1,所以不会有相邻元素包含在dp[i]中因此必然符合条件。
状态转移方程:
dp[i] = x0; 其中( i = 0 )
dp[i] = max(xi, dp[j] + xi)其中(j < i - 1);
最大值为val = max(dp[0],….,dp
);
但上述求解过程是在数据首尾不相连的情况下进行的,可题目条件是首尾相连。此时我们可以将原问题分解为两个子问题分别求解,然后选取他们解的最大值。假设数据为a0,…,an,则可将问题分解为a0,….,an-1(要首不要尾),a1,…..an(要尾不要首)
程序源码(c++):
#include <iostream> #include <vector> using namespace std; int max(int a, int b); class BadNeighbors { public: int solve(int a, int b, vector<int> &arr); int maxDonations(vector<int> donations); }; int main(void) { BadNeighbors badNb; // int arr[] = {10, 3, 2, 5, 7, 8}; int arr[] = {7, 7, 7, 7, 7, 7, 7}; int max; vector<int> vec(arr, arr + sizeof(arr) / sizeof(int)); max = badNb.maxDonations(vec); cout << max << endl; return 0; } int BadNeighbors::solve(int a, int b, vector<int> &arr) { int dp[b - a + 2]; int ans = 0; for(int i = a; i < b + 1; i++) { if(i == a) { dp[i] = arr[a]; ans = arr[a]; } else { dp[i] = arr[i]; for(int j = a; j < i - 1; j++) { dp[i] = max(dp[i], dp[j] + arr[i]); } if(dp[i] > ans) ans = dp[i]; } } return ans; } int BadNeighbors::maxDonations(vector<int> donations) { int n = donations.size(); int a = solve(1, n - 1, donations); int b = solve(0, n - 2, donations); if(a > b) return a; else return b; } int max(int a, int b) { if(a > b) return a; else return b; }
参考文章原文来自http://apps.topcoder.com/forums//?module=Thread&threadID=757580&start=0&mc=10重点内容
Hi. I think you’ve already solved this problem, but this will help whoever is learining dp. (as me)
Let’s supose we have an array ‘donations’ which is the amount of money form the person i
Let’s think a little bit and define the following
Let dp[i] be the maximum amount of money USING THE PERSON i and using zero or more persons less than i-1
It follows that
dp[0] = donations[0] (base case)
Then
dp[i] = max( donations[i] , dp[j] + donations[i] for every j
相关文章推荐
- C++动态规划之最长公子序列实例
- C++动态规划之背包问题解决方法
- C#使用动态规划解决0-1背包问题实例分析
- 动态规划
- C++ 动态规划
- DP(动态规划) 解游轮费用问题
- 动态规划的用法——01背包问题
- 动态规划的用法——01背包问题
- 《收集苹果》 动态规划入门
- 《DNA比对》蓝桥杯复赛试题
- 《背包问题》 动态规划
- 自顶向下动态规划解决最长公共子序列(LCS)问题
- 初学ACM - 半数集(Half Set)问题 NOJ 1010 / FOJ 1207
- 关于爬楼梯的动态规划算法
- 动态规划 --- hdu 1003 **
- DP问题各种模型的状态转移方程
- 0-1背包解题过程
- 背包问题
- USACO 3.2.2:Stringsobits
- 字符串编辑距离