您的位置:首页 > 其它

动态规划----切割钢条

2016-08-24 13:00 204 查看
动态规划方法通常用来求解最优化问题。动态规划算法设计步骤:

刻画一个最优解的结构特征。
递归定义最优解的值。
计算最优解的值,通常采用自底向上的方法。
利用计算出的信息构造一个最优解。

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

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

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

假定我们知道公司出售一段长度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

我们将钢条从左边切割下长度为i的一段,只对右边剩下的n-i的一段继续进行切割,对左边的一段不再进行切割。


#include<iostream>
#include<algorithm>

using namespace std;

int CUT_ROD(int *p, 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;
}

int main()
{
cout << "请输入钢条的长度(1<=n<=10):";
int n;
int p[11] = { 0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30 };
while (cin >> n)
{
cout << "最大收益为:" << CUT_ROD(p, n) << endl;
cout << "继续?(y/n):";
char ch;
cin >> ch;
if (ch == 'y')
{
cout << "请输入钢条的长度(1<=n<=10):";
continue;
}
else
break;
}
cout << __DATE__ << " " << __TIME__ << endl;
system("pause");
return 0;
}

运行结果:
请输入钢条的长度(1<=n<=10):10
最大收益为:30
继续?(y/n):y
请输入钢条的长度(1<=n<=10):9
最大收益为:25
继续?(y/n):y
请输入钢条的长度(1<=n<=10):8
最大收益为:22
继续?(y/n):n
Aug 24 2016 12:36:31
请按任意键继续. . .

在这个递归过程中,CUT_ROD会反复求解相同的子问题,因此当这个递归过程展开的时候,它的工作量会爆炸性的增长!对于长度为n的钢条,CUT_ROD显然考察了所有2^(n-1)中可能的切割方案!动态规划应该仔细安排求解顺序,对每个子问题只求解一次,并将结果保存下来。

带备忘录的自顶而下的方法:

#include<iostream>
#include<algorithm>

using namespace std;

int CUT_ROD2(int *p, int n, int *r)
{
if (r
!= -1)
return r
;
if (n == 0)
return 0;
int q = -1;
for (int i = 1; i <= n; i++)
q = max(q, p[i] + CUT_ROD2(p, n - i, r));
r
= q;
return q;
}

int main()
{
cout << "请输入钢条的长度(1<=n<=10):";
int n;
int p[11] = { 0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30 };
while (cin >> n)
{
int *r = new int[n+1];//备忘录
memset(r, -1, sizeof(int)*(n + 1));
cout << "最大收益为:" << CUT_ROD2(p, n, r) << endl;
cout << "继续?(y/n):";
char ch;
cin >> ch;
if (ch == 'y')
{
cout << "请输入钢条的长度(1<=n<=10):";
continue;
}
else
break;
free(r);
}
cout << __DATE__ << " " << __TIME__ << endl;
system("pause");
return 0;
}

运行结果和上一题一样!

自底向上版本:

#include<iostream>
#include<algorithm>

using namespace std;

int CUT_ROD3(int *p, int n, int *r)
{
for (int i = 1; i <= n; ++i)
{
int q = -1;
for (int j = 1; j <= i; ++j)
{
q = max(q, p[j] + r[i - j]);
}
r[i] = q;
}
return r
;
}

int main()
{
cout << "请输入钢条的长度(1<=n<=10):";
int n;
int p[11] = { 0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30 };
while (cin >> n)
{
int *r = new int[n + 1];//备忘录
memset(r, 0, sizeof(int)*(n + 1));
cout << "最大收益为:" << CUT_ROD3(p, n, r) << endl;
cout << "继续?(y/n):";
char ch;
cin >> ch;
if (ch == 'y' || ch == 'Y')
{
cout << "请输入钢条的长度(1<=n<=10):";
continue;
}
else
break;
free(r);
}
cout << __DATE__ << " " << __TIME__ << endl;
system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: