回溯法实验(0-1背包问题)教学文案
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
回溯法实验(0-1 背包
问题)
算法分析与设计实验报告第丄次附加实验
巔I 軌鬻
123^EC70?1O
牧品价值分别为:
12345678? 10
妆品重量和忙值分别为;
<2^2> <3,3> <4.4>
O^SJ C9,9) <18,10>
在实验中并没有生成多组数据,进行比较,也没有利用随机生 成函数,因为在这种有实际有关联的问题中,利用随机生成函数生 成的数
据是十分的不合适的,在此我们只需要验证该程序是否正确 即可。
0-1背包问题和之前的最优装载其实质上一样的,都是利用 解空间树,通过深度优先搜索子集树,通过利用上界函数和一些剪 枝策略,从而得到最优解。
由于数据较小,所以时间上并不能反映 出什么东西。
当输入的数据有解时:
测试结果
实验分析
当输入的数据无解时:
当输入的数据稍微大点时:
四回溯法X FUFO ORe\Debuq\zeno cnejext
阀品上数为:M
在这一章的回溯算法中,我们用的比较多的就是;利用子集
树 来进行问题的探索,就例如上图是典型的一种子集树,在最优装 载、0-1背包都是利用了这种满二叉树的子集树进行求解,然后通 过深度优先的策略,利用约束函数和上界函数,将一些不符合条件 或者不包含最优解的分支减掉,从而提高程序
的效率。
对于
0-1背
包问题我们基本上在每一个算法中都有这么一个实例,足以说明这 个问题是多么经典的一个问题啊,通过几个不同的算法求解这一问 题,我也总算对该问题有了一定的了解。
实验得分
附录:
完整代码(回溯法)
〃0-1背包问题 回溯法求解
#i nclude <iostream> using namespacestd;
template <class Typew, class Typep> class Knap //Knap 类记录解空间树的结点信息
{
template <class Typew, class Typep>
friend Typep Knapsack(Typep [],Typew [],Typew, int );
private :
Typep Bound( int i);
//计算上界的函数
实验心得 助教签名
void Backtrack( int i); //回溯求最优解函数
Typew c; //背包容量
int n; //物品数
Typew *w; //物品重量数组|
Typep *p; //物品价值数组
Typew cw; //当前重量
Typep cp; //当前价值
Typep bestp; //当前最后价值
};
template <class Typew, class Typep>
Typep Knapsack(Typep p[],Typew w[],Typew c, int n); //声明背包问题求解函数
template < class Type>
in li ne void Swap (Type &a,Type & b); // 声明交换函数
template <class Type>
void BubbleSort(Type a[], int n); // 声明冒泡排序函数
int main()
{
int n ; //物品数
int c ; //背包容量
cout«"物品个数为:";
cin»n;
cout«"背包容量为:";
cin> >c;
int *p = new int [n]; //物品价值下标从1开始
int *w = new int [n]; //物品重量下标从1开始
cout«"物品重量分别为:"<<e ndl;
for (int i=1; i<=n; i++)
{
cin> >w[i];
}
cout«"物品价值分别为:"<<e ndl;
for (int i=1; i<=n; i++) //以二元组(重量,价值)的形式输出每
物品的信息
{
cin> >p[i];
}
coutvv "物品重量和价值分别为:"<<e ndl;
for (int i=1; i<=n; i++) //以二元组(重量,价值)的形式输出每个物
品的信息
{
coutvv "(" <<w[i]<< "," <<p[i]<< ")";
}
coutvve ndl;
coutvv "背包能装下的最大价值为:"<<Knapsack(p,w,c,n)<<endl; //输出结果
system( "pause");
return 0;
}
template vclass Typew, class Typep>
void Knap<Typew,Typep>::Backtrack( int i)
{
if (i>n) //到达叶子节点
{
bestp = cp; //更新最优值
return ;
}
if (cw + w[i] <= c) // 进入左子树
{
cw += w[i];
cp += p[i];
Backtrack(i+1); // 回溯
//回溯结束回到当前根结点
cw -= w[i];
cp -= p[i];
}
//进入右子树,条件是上界值比当前最优值大,否则就将右子树剪掉
if (Bound(i+1)>bestp)
{
Backtrack(i+1);
}
}
template <class Typew, class Typep>
Typep KnapvTypew, Typep>::Bound( int i) //计算上界
{
Typew cleft = c - cw; // 剩余容量
Typep b = cp;
//以物品单位重量价值递减序装入物品
while (i <= n && w[i] <= cleft)
{
cleft -= w[i];
b += p[i];
i++;
}
//如果背包剩余容量不足以装下一个物品
if (i <= n)
{
b += p[i]/w[i] * cleft; //则将物品的部分装入到背包中}
return b;
}
class Object //定义对象类,作用相当于结构体
{
template vclass Typew, class Typep>
friend Typep Knapsack(Typep[],Typew [],Typew, int ); public : int operator >= (Object a) const // 符号重载函数,重载>=符号{
return (d>=a.d);
}
private :
int ID; // 编号
float d; //单位重量的价值
};
template <class Typew, class Typep>
Typep Knapsack(Typep p[],Typew w[],Typew c, int n)
{
// 为Knap::Backtrack 初始化
Typew W = 0;
Typep P = 0;
Object *Q = newObject[n]; // 创建Object 类的对象数组| //初始化Object类的对象数组|
for (int i=1; i<=n; i++)
{
Q[i-1] .ID = i;
Q[i-1].d = 1.0 * p[i]/w[i];
P += p[i];
W += w[i];
}
if (W <= c) //装入所有物品
{
return P;
}
//依物品单位重量价值降序排序
BubbleSort(Q, n);
Knap<Typew,Typep> K; // 创建Knap的对象K
K.p = n ewTypep[ n+1];
K.w = n ewTypew [n+1];
for (int i=1; i<=n; i++)
{
K.p[i] = p[Q[i-1]」D];
K.w[i] = w[Q[i-1].ID];
}
//初始化K
K.cp = 0;
K.cw = 0;
K.c = c;
K.n = n;
K.bestp = 0;
//回溯搜索
K.Backtrack(1);
delete []Q;
delete []K.w;
delete []K.p;
return K.bestp; // 返回最优解
} template <class Type>
void BubbleSort(Type a[], int n) {
//记录一次遍历中是否有元素的交换
bool excha nge;
for (int i=0; i<n-1;i++)
{
exchange = false ;
for (int j=i+1; j<=n-1; j++)
{
if (a[j]>=a[j-1])
{
Swap(a[j],a[j-1]); exchange = true ;
}
}
//如果这次遍历没有元素的交换,那么排序结束
if (exchange==false )
{
break ;
}
}
} template < class Type>
inline void Swap (Type &a,Type &b) // 交换函数{
Type temp = a; a = b;
b = temp;
}。