动态规划求不相邻的最大子数组和

来源:互联网 发布:电气自动化软件 编辑:程序博客网 时间:2024/04/29 16:18

其实这个问题原题是这样描述的:

    有N个节点,每两个节点相邻,每个节点只与2个节点相邻,因此,N个顶点有N-1条边。每一条边上都有权值wi,定义节点i到节点i+1的边为wi。
    求:不相邻的权值和最大的边的集合。
对于这个问题可能看起来不是很好处理,把问题更加规范化一些:给出一个数组,求出其中一个子集,使得子集中每个元素在原数组中两两都不相邻并使子集的和最大。

因为不能选择两个相邻的元素,那么对于第i个元素的选择的可能性就包含选择i和不选择i个元素,至于选与不选其实是和第i-1个元素有直接关系的。

考虑两种情况:

1> 选择i,那么第i-1个元素一定不能选

2> 不选择i,那么第i-1个元素是可以选,也可以不选的,这决定于第i-2个元素对i-1的影响。

从这两种情况中可以看出,如果知道第i-1次被选中和不被选中时前i个元素(元素下标从0开始计算)了最大子集和,那么我们可以算出选择i和不选择i各可以获得的最大子集和。

那么我们可以得到一个这样的公式, 其中DS[i]记录第i个元素被选中时的前i+1个元素的最大子集和。 NS[i]记录第i个元素未被选中时的前i+1个元素的最大子集和

DS[i] = NS[i-1]+ data[i]; 

NS[i] = max(NS[i-1], DS[i-1])

接下来看一下例子,假设现在有一个8个元素的数组:

1       7       4       0       9       4       8       8

那么 NS数组为:

0       1       7       7       7       16      16      24

DS数组为

1       7       5       7       16      11      24      24


下面是程序的代码

#include <iostream>#include <string.h>#include <stdlib.h>using namespace std;#define NMax 1000int data[NMax];int table[NMax][2];int GetMaxSubsetSum(int len){memset(table, 0 , sizeof(table));//第0行表示NS,表示该元素未被选中//第一行表示DS,表示该元素被选中table[0][0] = 0;table[0][1] = data[0];//动态规划 过程for (int i = 1; i < len; ++i){table[i][0] = max(table[i-1][1], table[i-1][0]);table[i][1] = table[i-1][0] + data[i];}//打印原始数组for (int i = 0; i < len; ++i)cout << data[i] <<"\t";cout <<endl;//打印NS数组for (int i = 0; i < len; ++i)cout << table[i][0] <<"\t";cout <<endl;//打印DS数组for (int i = 0; i < len; ++i)cout << table[i][1] <<"\t";cout <<endl;//返回整个数组的最大值return max(table[len-1][0], table[len-1][1]);}int main(){int len; cin >> len;if (len <= 0)return 1;for (int i = 0; i < len ; ++i){data[i] = rand()% 10;}cout << GetMaxSubsetSum(len)<<endl;}