动态规划之三:剪绳子变形之切割杆

问题:现在已知有一个长度为n的切割杆,且1~n长度对应的价值存储在prices[n]数组中,将其进行若干次切割,求其达到的最大价值?

      通过问题的叙述我们可以发现,和前一篇讲解的动态规划之二:剪绳子问题很相似,都属于动态规划的内容,因此我们就用动态规划的思想来解决问题。

      现在使用形式化语言来描述问题规模的最大价值状态,即f(n)表示长度为n的切割杆的最大价值。prices[n]数组中存储对应长度为1~n的价值并且是随机的,也就是说prices[2]的价值并不比prices[1]的价值大。因此假设我们第一次切割的长度为i,其最大价值为f(i),剩余的切割杆的长度为n-i,其最大价值为f(n-i):

使用具体示例进行分析:

    当n=0时,f(0)= 0;

    当n=1时,f(1)= prices[0];

    当n=2时,f(2)= max( prices[1] , f(1)+f(1) );

    当n=3时,f(3)= max( prices[2] , f(1)+f(2) );

    当n=4时,f(4)= max( prices[3] , f(1)+f(3) , f(2)+f(2) );

    …….

                  f(n)=max( prices[n-1] , f(1)+f(n-1) , f(2)+f(n-2) , …,f(i)+f(n-i) )       ( i>=0 && i<n/2 )

由此,我们可以知道状态转移函数为:f(n)= max( prices[n-1] , f(i) *+f(n-i)  ) , 其中i的取值范围为(i>0&&i<=n/2)。

程序结果如下:

#include<iostream>  
using namespace std;
#define size 100  //表格的大小  

int Line_Max(int a[], int n) {
	if (n <= 0)
		return 0;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= i / 2; j++)     //比较的范围为:(1,n/2)  
			if (a[j] +a[i - j]>a[i])
				a[i] = a[j] + a[i - j];
	return a[n];
}

int main() {
	int table[size] = { 0 };
	int prices[size];
	int n;
	cin >> n;
	for (int i = 0; i < n; i++)
		cin >> prices[i];
	for (int i = 1; i <= n; i++)
		table[i] = prices[i-1];//对表格用prices数组进行初始化,用来存储长度为i的最大乘积值
	cout <<"长度为"<<n<<"的最大价值为:"<< Line_Max(table, n) << endl;
	return 0;
}

点赞