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