- 基本思想:问题的最优解如果可以由子问题的最优解推导得到,则可以先求解子问题的最优解,再通过子问题的解构造原问题的最优解;若子问题有较多的重复出现,则可以自底向上从最终子问题向原问题逐步求解。
- 使用条件:原问题无后效性,具有有最优子结构和重叠子问题。
- 最优子结构:
- 一个问题的优化解包含了子问题的优化解
- 缩小子问题集合,只需那些优化问题中包含的子问题,降低实现复杂性
- 重叠子问题:在问题的求解过程中,很多子问题的解将被多次使用。
- 最优子结构:
- 算法的设计步骤:
- 找出最优解的性质,并刻画其结构特征
- 递归地定义最优值
- 以自底向上地方式计算最优值
- 根据计算最优值得到的信息,构造最优解
- 特点:
- 把原始问题划分成一系列子问题;
- 每个子问题仅求解一次,并将结果保存在表中,以后用到时直接存取,不重复计算,节省计算时间
- 自底向上地计算。
- 整体问题最优解取决于子问题的最优解(状态转移方程)
- 本章共学习例题有
- 1.矩阵连乘问题
- 2.最长公共子序列
- 3.最大字段和
- 4.凸多边形最优三角剖分
- 5.多边形游戏
- 6.图像压缩
- 7.0-1背包问题
- 8.最优二叉搜索树
- 9.独立任务最优调度问题
- 10.最优批处理问题
- 11.石子合并问题
- 12.数字三角形问题
- 13.租用游艇问题
- 14.最小m段和问题
例题:0-1背包问题
问题描述:
给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为C。问应如何选择装入背包的物品,使得装入背包中物品的总价值最大?
本题存在约束条件
即,要找到一个物品的组合,使得它们的重量小于等于最大容量,并且其价值最大。
设所给0-1背包问题的子问题的最优值为m[i][j], m[i][j]的含义是是在背包容量为j,可选物品为1—— i 时的0-1背包问题的最优值。由0-1背包问题的最优子结构性质,可建立计算m[i][j]的递归式如下:
即在背包容量允许的情况下如果不放入第 i 件物品,则问题转换为“前i - 1件物品放入容量为 j 的背包中”;如果放入第 i 件物品,则问题转化为“前i - 1件物品放入容量为 j - w[i] 的背包中”,此时的最大值为 max{m[i - 1][j], m[i - 1][j - w[i]] + v[i] };若背包容量不足,则只能转换为“前i - 1件物品放入容量为 j 的背包中”。
这个时候我们就要定义一个表格m[n][w]。这个表的意义为:当我到拿第 i件物品的阶段时,当前的剩余容量 j下的最大价值。我们要根据递推式从表格的左上角开始,一直推理到表格的右下角,即当我到拿完所有物品的时,当前的剩余容量 w下的最大价值
#include<iostream>
#include<stdlib.h>
#include<fstream>
using namespace std;
class mystrious_ranch
{
private:
int n,w;
int *val,*wei,**m,*p;
ifstream in;
ofstream out;
void fopen()
{
in.open("input.txt");
out.open("output.txt");
}
void read()
{
in>>n>>w;
if(n<1||w<1)
{
cout<<"物品的数量或背包的承重量不合理"<<endl;
exit(0);
}
val=new int[n+1];
wei=new int[n+1];
int i;
for(i=1;i<n+1;i++)
{
in>>val[i];
if(val[i]<1)
{
cout<<"物品的价值不合理"<<endl;
exit(0);
}
}
for(i=1;i<n+1;i++)
{
in>>wei[i];
if(wei[i]<1)
{
cout<<"物品的重量不合理"<<endl;
exit(0);
}
}
m=new int*[n+1];
for(i=0;i<n+1;i++)
m[i]=new int[w+1];
p=new int[n+1];
for(i=0;i<n+1;i++)
m[i][0]=0;
for(i=0;i<w+1;i++)
m[0][i]=0;
}
void output()
{
out<<m[n][w]<<endl;
int i,j;
i=n,j=w;
/*从i=n,j=w开始寻找,如果ks(i-1,j)=ks(i,j),说明第i个物品没有被选中,从ks(i-1,j)继续寻找。
否则,表示第i个物品已被选中,则从ks(i-1,j-wi)开始寻找。*/
while(1)
{
if(m[i][j]==m[i-1][j-1])//第i个没被选上
p[i]=0;
else
{
p[i]=1;
j-=wei[i];
}
i--;
if(i==0)
break;
}
for(i=1;i<n+1;i++)
out<<p[i]<<" ";
}
public:
void loot()
{
fopen();
read();
int i,j;
for(i=1;i<n+1;i++)
{
for(j=1;j<w+1;j++)
{
if(wei[i]>j)
m[i][j]=m[i-1][j];
else
m[i][j]=max(m[i-1][j],m[i-1][j-wei[i]]+val[i]);
}
}
output();
}
~mystrious_ranch()
{
delete[]m;
delete[]p;
in.close();
out.close();
}
};
int main()
{
mystrious_ranch mr;
mr.loot();
return 0;
}