钢条切割
自顶向下的递归实现
CUT-ROD(p,n)
if n==0
return 0
q=-~~
for i to n
q=max(q,p[i]+CUT_ROD(p,n-1)
return q
C++实现
#include <iostream>
#include <cmath>
using namespace std;
int p[10]={1,5,8,9,10,17,17,20,24,30};
int dp(int n)
{
if (n==0)
return 0;
int q = -10000;
for (int i = 1; i <= n; ++i)
{
q=max(q,p[i-1]+dp(n-i));
cout<<"n="<<n<<" i="<<i<<" q="<<q<<endl;
}
return q;
}
int main(int argc, char const *argv[])
{
cout<<dp(4)<<endl;
return 0;
}
CUT_ROD效率极慢,因为反复利用相同的参数值对自身递归调用
带备忘的自顶向下方法
仍按自然方法递归,但是过程中会保存每个问题的子解
mem-cut-rod(p, n)
1 let r[0…n] be a new array
2 for i=0 to n
3 r[i] = -∞
4 return mem-cut-rod-aux(p, n, r)
mem-cut-rod-aux(p, n, r)
1 if r[n] >= 0
2 return r[n]
3 if n == 0
4 q = 0
5 else
6 q = -∞
7 for i=1 to n
8 q = max(q, p[i] + mem-cut-rod-aux(p, n-i, r))
9 r[n] = q
10 return q
C++实现方法(二)
#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;
int p[10]={1,5,8,9,10,17,17,20,24,30};
int r[1000];
int dp(int n)
{
if(r[n]>0)
return r[n];
int q;
if(n==0)
return 0;
else
{
q = -20000;
for (int i = 1; i <= n; ++i)
{
q = max(q,p[i-1]+dp(n-i));
}
r[n]=q;
return q;
}
}
int main(int argc, char const *argv[])
{
memset(r,0x80000000,sizeof(r));
for(int i = 1;i<=10;i++)
cout<<dp(i)<<endl;
return 0;
}
java实现方法
public class CutRob {
public static int[] prices = {1,5,8,9,10,17,17,20,24,30};
/** 自顶向下*/
public static int mem_cut_rod(int n){
int[] dp = new int[n+1]; // 辅助数组dp
Arrays.fill(dp, Integer.MIN_VALUE); // 初始化为负无穷
return mem_cut_rod_aux(n, dp);
}
/** 自顶向下法的辅助函数*/
private static int mem_cut_rod_aux(int n, int[] dp) {
if(dp[n] >= 0) return dp[n]; // 如果子问题已经解过,直接返回
int max = Integer.MIN_VALUE;
if(n==0) max = 0; // 如果长度为0,则最大收益为0
else{ // 长度若不为0
for(int i = 1; i<=n; i++) // 找到最大收益
max = Math.max(max, prices[i-1] + mem_cut_rod_aux(n-i, dp));
}
dp[n] = max; // 把计算得到的最大收益存入结果
return max; // 返回结果
}
public static void main(String[] args) {
for(int i=1; i<=prices.length; i++)
System.out.println("长度为"+i+"的最大收益为:"+mem_cut_rod(i));
}
}
自底向上的方法
需要定义子集规模的概念
使得任何子问题的求解都是通过更小问题的子问题求解
讲子问题按照规模先排序,按有小到大循序求解
伪代码
bottom-up-cut-rod(p, n)
1 let r[0…n] be a new array
2 r[0] = 0
3 for j=1 to n
4 q = -∞
5 for i=1 to j
6 q = max(q, p[i] + r[j-i])
7 r[j] = q
8 return r[n]
CPP实现方法
#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;
int p[10]={1,5,8,9,10,17,17,20,24,30};
int r[1000];
int dp(int n)
{
r[0]=0;
for (int i = 1; i <= n; ++i)
{
int q = 0x80000000;
for (int j = 1; j <= i; ++j)
{
q = max(q,p[j-1]+r[i-j]);
//只需要考虑当前的状态
}
r[i]=q;
}
return r[n];
}
int main(int argc, char const *argv[])
{
memset(r,0x80000000,sizeof(r));
for(int i = 1;i<=10;i++)
cout<<dp(i)<<endl;
return 0;
}
java实现方法
public class CutRob {
public static int[] prices = {1,5,8,9,10,17,17,20,24,30};
/** 自底向上法*/
private static int bottom_up_cut_rod(int n){
int[] dp = new int[n+1];
dp[0] = 0;
for(int j=1; j<=n; j++){
int max = Integer.MIN_VALUE;
for(int i=1; i<=j; i++){
max = Math.max(max, prices[i-1] + dp[j-i]);
}
dp[j] = max;
}
return dp[n];
}
public static void main(String[] args) {
for(int i=1; i<=prices.length; i++)
System.out.println("长度为"+i+"的最大收益为:"+bottom_up_cut_rod(i));
}
}