码迷,mamicode.com
首页 > 编程语言 > 详细

算法导论---------动态规划之钢条切割

时间:2014-12-13 09:37:19      阅读:270      评论:0      收藏:0      [点我收藏+]

标签:算法导论   动态规划   钢条切割   

动态规划方法通常用来求解最优化问题。动态规划算法设计步骤:

1.刻画一个最优解的结构特征。

2.递归定义最优解的值。

3.计算最优解的值,通常采用自底向上的方法。

4.利用计算出的信息构造一个最优解。

动态规划的实现方法:

带备忘的自顶向下法:此方法仍按自然的递归形式编写过程,但过程会保存每个子问题的解(通常保存在一个数组或散列表中)。当需要一个子问题的解时,过程首先检查是否已经保存过此解。如果是,则直接返回保存的值,从而节省了计算时间;否则,按通常方式计算这个子问题。

自底向上法:这种方法一般需要恰当定义子问题“规模”的概念,使得任何子问题的求解都依赖于“更小的”子问题的求解。因而我们可以将子问题按规模排序,按由小至大的顺序进行求解。当求解某个子问题时,它所依赖的那些更小的子问题都已经求解完毕,结果已经保存。每个子问题只需要求解一次,当我们求解它(也是第一次遇到它)时,它的所有前提子问题都已求解完成。

问题:公司购买长钢条,将其切割为短钢条出售。切割工序本身没有成本支出。公司管理层希望知道最佳的切割方案。

假定我们知道公司出售一段长度i英寸的钢条的价格为pi(i=1,2,...,单位为美元)。钢条的长度均为整英寸。图给出了一个价格表的样例。

长度   i    1       2      3      4        5       6        7        8        9        10

价格 Pi    1      5      8       9      10      17      17      20      24      30

切割钢条的问题是这样的:给定一段长度为n英寸的钢条和一个价格表Pi,求切割方案,使得销售收益Rn最大。

当然,如果长度为n英寸的钢条价格Pn足够大,最优解可能就是完全不需要切割。

对于上述价格表样例,我们可以观察所有最优收益值Ri及对应的最优解方案:

R1 = 1,切割方案1 = 1(无切割)

R2 = 5,切割方案2 = 2(无切割)

R3 = 8, 切割方案3 = 3(无切割)

R4 = 10, 切割方案4 = 2 + 2

R5 = 13, 切割方案5 = 2 + 3

R6 = 17, 切割方案6 = 6(无切割)

R7 = 18, 切割方案7 = 1 + 6或7 = 2 + 2 + 3

R8 = 22, 切割方案8 = 2 + 6

R9 = 25, 切割方案9 = 3 + 6

R10 = 30,切割方案10 = 10(无切割)

更一般地,对于Rn(n >= 1),我们可以用更短的钢条的最优切割收益来描述它:

Rn = max(Pn, R1 + Rn-1, R2 + Rn-2,...,Rn-1 + R1)

首先将钢条切割为长度为i和n - i两段,接着求解这两段的最优切割收益Ri和Rn - i(每种方案的最优收益为两段的最优收益之和),由于无法预知哪种方案会获得最优收益,我们必须考察所有可能的i,选取其中收益最大者。如果直接出售原钢条会获得最大收益,我们当然可以选择不做任何切割。

#include<iostream>
#include<algorithm>
#include<vector>
#include<utility>
using namespace std;

/*------------------------------------------------------------------------------------------
/*  用朴素的递归的方法的求解:递归的求解每一个子问题,当碰到相同的子问题重新求解,重点理解递归的过程
/*  此方法最大的缺点是:每当n增加1的时候,程序运行时间差不多就会增加一倍,
/*  其工作量会爆炸性的增长。
/*-------------------------------------------------------------------------------------------*/
int cut_rod(int *p,const int &n)
{
	if (n == 0)
		return 0;
	int q = -1;
	for (int i = 1; i <= n; ++i)
	{
		q = max(q, p[i]+cut_rod(p, n - i));
	}
	return q;
}

//使用动态规划的方法:在求其子问题的时候保存其子问题的结果,当遇到相同的子问题的时候不用再次求解
//而是查找求过的子问题直接调用
//第二种方法是:自顶向下cut_tod过程,加入了备忘机制
int memoized_cut_rod_aux(int *p, int n, int *r)
{
	if (r[n] >= 0)
		return r[n];

	int q = -1;
	if (n == 0)
		q = 0;
	else
	{
		for (int i = 1; i <= n; ++i)
			q = max(q, p[i] + memoized_cut_rod_aux(p, n - i, r));
	}

	r[n] = q;//保存子问题的一个最优解

	return q;
}

int memoized_cut_rod(int *p, const int n)
{
	int r[11] = {0};
	for (int i = 1; i <= n; i++)
		r[i] = -1;
	int q = memoized_cut_rod_aux(p, n, r);
	return q;
}

//第三种方法:自底向上的方法
int bottom_up_ut_rod(int *p, int n)
{
	int r[11] = { 0 };
	int q = 0;
	for (int j = 1; j <= n; ++j)
	{
		for (int i = 1; i <= j; ++i)
			q = max(q, p[i] + r[j - i]);
		r[j] = q;
	}

	return r[n];
}
//重构:不仅输出长度为n的时候最大收益还输出一个最优切割方案
pair<vector<int>, vector<int>> extended_bottom_up_cut_rod(int *p, int n)
{
	int r[11] = { 0 };
	int s[11] = { 0 };
	pair< vector<int>, vector<int> > result;
	result.first.push_back(0);
	result.second.push_back(0);
	for (int j = 1; j <= n; ++j)
	{
		int q = -1;
		for (int i = 1; i <= j; ++i)
		{
			if (q < p[i] + r[j - i])
			{
				q = p[i] + r[j - i];
				s[j] = i;
			}
		}
		r[j] = q;
		result.first.push_back(r[j]);
		result.second.push_back(s[j]);
	}

	return result;
}
//输出收益和方案
void print_cut_rod_solution(int *p,int n)
{
	pair< vector<int>, vector<int> > result;
	result = extended_bottom_up_cut_rod(p, n);
	vector<int> r = result.first;
	vector<int> s = result.second;
	cout << "钢条切割最大收益为: ";
	cout << r[n] << endl;
	cout << "最佳切割方式: " << endl;
	while (n > 0)
	{
		cout << s[n];
		n = n - s[n];
		cout << endl;
	} 
}

int main()
{
	char ch;
	int p[11] = { 0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30 };
	int n;
	while (cin >> n)
	{
		cout << "普通递归方法: " << cut_rod(p, n) << endl;
		cout << "带备忘录的自顶向下法: " << memoized_cut_rod(p, n) << endl;
		cout << "自底向下法: " << bottom_up_ut_rod(p, n) << endl;
		print_cut_rod_solution(p, n);
		cout << "请输入 y or n:";
		cin >> ch;
		if (ch == 'n')
			break;
		else
		{
			cout << "请输入继续输入适当的数n:";
			continue;
		}
	}

}

bubuko.com,布布扣



算法导论---------动态规划之钢条切割

标签:算法导论   动态规划   钢条切割   

原文地址:http://blog.csdn.net/chenxun_2010/article/details/41904847

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!