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


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

  1. 有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 1000

int 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;
}

    原文作者:动态规划
    原文地址: https://blog.csdn.net/realxie/article/details/8063885
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞