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

41 篇文章 1 订阅


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

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



  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值