算法第五章上机实践报告
一、题目描述
7-2 最小重量机器设计问题 (25 分)
设某一机器由n个部件组成,每一种部件都可以从m个不同的供应商处购得。设wij?是从供应商j 处购得的部件i的重量,cij?是相应的价格。 试设计一个算法,给出总价格不超过d的最小重量机器设计。
输入格式:
第一行有3 个正整数n ,m和d, 0 输出计算出的最小重量,以及每个部件的供应商 在这里给出相应的输出。例如: 每个零件有m个供应商可以选择,这样有m^n种可选方案,其中就有问题想要的最优解。然后把解空间组织成一棵m叉树,然后以深度优先搜索的方式纵深向下搜索,当不满足约束函数(即约束条件d)或者是限界函数(即搜索过的可行方案中最小的质量总和)时回溯,寻求尝试另一种方案,然后继续纵深向下搜索。当向下搜索到叶子节点时,不再向下搜索,转去更新最优值。 解空间是穷举所有可能解的空间,{(1,3,1),(1,3,2),(1,3,3)} 解空间树是一棵m叉树,从根节点出发后,每一层分别表示一个部件的不同供应商,往下延伸共n层。 每个结点有两个状态值,分别是当前的总价格、当前的总重量。 1.回溯法在问题的解空间树中,按深度优先策略,从根结点出发搜索解空间树。算法搜索至解空间树的任意一点时,先判断该结点是否包含问题的解。如果肯定不包含,则跳过对该结点为根的子树的搜索,逐层向其祖先结点回溯;否则,进入该子树,继续按深度优先策略搜索。 2.回溯法的基本步骤: (1)针对所给问题,定义问题的解空间; (2)确定易于搜索的解空间结构; (3)以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。 3.常用剪枝函数: (1)用约束函数在扩展结点处剪去不满足约束的子树; (2) 用限界函数剪去得不到最优解的子树。 4.通解模板如下: 5. 在用回溯法求解问题时,常常遇到两种典型的解空间树: 遍历子集树函数: ②排列树:当所给问题是确定n个元素的满足某种性质的排列时,相应的解空间树称为排列树。例:旅行售货员问题。 遍历排列树函数:输出格式:
输入样例:
3 3 4
1 2 3
3 2 1
2 2 2
1 2 3
3 2 1
2 2 2
输出样例:
4
1 3 1
二、算法分析
1. 请用回溯法的方法分析“最小重量机器设计问题”
1.1说明“最小重量机器设计问题"的解空间
1.2 说明“最小重量机器设计问题"的解空间树
1.3 在遍历解空间树的过程中,每个结点的状态值是什么
三、问题求解代码
#include
四、心得体会
对回溯算法的理解
void backtrack (int t) //回溯法对解空间作深度优先搜索,因此,在一般情况下用递归方法实现回溯法
{
if (t>n) output(x); //算法已搜索到一个叶结点,输出该结果
else
for (int i=f(n,t);i<=g(n,t);i++) //f(n,t),g(n,t)分别表示扩展结点的子树的起始编号和终止编号。尝试这些选择
{
x[t]=h(i); //H(i)表示第i个可选值
if (constraint(t)&&bound(t)) //分别表示约束函数和限界函数
backtrack(t+1);
}
}
①子集树:当所给的问题是从n个元素的集合S中找出满足某种性质的子集时,相应的解空间树成为子集树。例:0-1背包问题。void Backtrack(int t)
{//以深度优先的方式遍历第t层中的某棵子树
if(t>n) { Output(x); return; }
if (……)
{ x[t]=1; Backtrack(t+1); }
if (……)
{ x[t]=0; Backtrack(t+1); }
}
void Swap(int *p,int *q)
{ int temp;
temp=*p;*p=*q;*q=temp; }
void Backtrack(int t)
{ //遍历第t层结点为根的某棵子树
int i;
if(t>n) { Output(x); return; }
for(i=t;i<=n;i++)
//x[1]~x[t-1]确定,获得x[t]~x[n]的不同组合
if(……)
{ Swap(&x[t],&x[i]);
Backtrack(t+1);
Swap(&x[t],&x[i]); }
}