[算法导论]钢材切割

 
#include<stdio.h>
#include<iostream>
#include<limits.h>

using namespace std;
const int Length = 10;
int s[Length + 1] = {0}, r[Length + 1] = {0};

int Max(int a, int b);
int CutRod(int profit[], int len);
int MemorizedCutRodAux(int profit[], int len, int r[]);
int MemorizedCutRod(int profit[], int len);
int BottomUpCutRod(int profit[], int len);
int ExtendedBottomUpCutRod(int profit[], int len);
void PrintCutRodSolution(int profit[], int len);

int main ()
{
	int profit[Length + 1] = {0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30};
	printf("自顶向下递归\nprofit = %d\n", CutRod(profit, 7));//假设待切钢材长度为7
	printf("带备忘的自顶向下递归\nprofit = %d\n", MemorizedCutRod(profit, 7));
	printf("自底向上法\nprofit = %d\n", BottomUpCutRod(profit, 7));
    printf("最优化的解决方案:\n");
    PrintCutRodSolution(profit, 7);
}

int CutRod(int profit[], int len)
{
	if(len == 0)//首先设置递归的返回条件
	return 0;

	int income = -1000;//初始化 以便下面可以正确计算
	for(int i = 1; i <= len; i++)
	{//income每次返回
		income = Max(income, profit[i] + CutRod(profit, len - i));//成树形 见图CutRod
	}
	return income;
}
//动态规划:避免反复求解相同的子问题 对每个子问题仅求解一次 但额外空间消耗大
//带备忘的自顶向下法
int MemorizedCutRod(int profit[], int len)
{
	int r[len + 1];//与自然递归的不同之处 r数组用于保存子问题的解
	for(int i = 0; i <= len; i++)
	{//对未知值进行初始化的常用方法 已知收益均非负
		r[i] = INT_MIN;
	}
	return MemorizedCutRodAux(profit, len, r);
//Aux是auxiliary(辅助)
}

int MemorizedCutRodAux(int profit[], int len, int r[])//见图片MemorizedCutRodAux
{
    int income;
	if(r[len] > 0)//证明长度为len的子问题已经求解过了
	return r[len];//比自然递归的优秀之处

	if(len == 0)
    income = 0;

    else
    {
         income = INT_MIN;
         for(int i = 1; i <= len; i++)
         {
             income = Max(income, profit[i] + MemorizedCutRodAux(profit, len - i, r));
         }
    }
    r[len] = income;//对子问题解的保存 即带备忘性质
    return income;}

//自底向上法 一般需要定义子问题的规模
//使得任何子问题的求解都只依赖于更小子问题的求解
//因此可以将子问题按照规模进行排序 当求解某个子问题时 所依赖的更小的问题已经求解完毕
int BottomUpCutRod(int profit[], int len)
{
    int r[Length + 1];
    r[0] = 0;//长度为0的钢条没有收益
    int income;
    for(int j = 1; j <= len; j++)
    {
        income = INT_MIN;
        for(int i = 1; i <= j; i++)
        {//可以直接访问r[j-i]来获得长度为j-i的小问题的解而不需要进行递归调用
            income = Max(income, profit[i] + r[j - i]);
        }
        r[j] = income;
    }
    return r[len];
}

int ExtendedBottomUpCutRod(int profit[], int len)
{
    int income;
    r[0] = 0;
    for(int j = 1; j <= len; j++)
    {
        income = INT_MIN;
        for(int i = 1; i <= j; i++)
        {
            if(income < profit[i] + r[j - i])
            {//在求解规模为j的子问题的时候将第一段钢条的最优切割长度i保存在s[j]中
                income = profit[i] + r[j - i];
                s[j] = i;
            }
            r[j] = income;
        }
    }
    return r[len];
}

void PrintCutRodSolution(int profit[], int len)
{
    ExtendedBottomUpCutRod(profit, len);
    while(len > 0)
    {
        cout <<s[len] << "  ";
        len -= s[len];
    }
}
int Max(int a, int b)
{
	return a > b ? a : b;
}

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值