算法第五章《回溯法》上机实践报告
一.实践题目名称
最小重量机器设计问题
二.问题描述
设某一机器由n个部件组成,每一种部件都可以从m个不同的供应商处购得。设wij是从供应商j 处购得的部件i的重量,cij是相应的价格。 试设计一个算法,给出总价格不超过d的最小重量机器设计。
输入格式:
第一行有3 个正整数n ,m和d, 0<n<30, 0<m<30, 接下来的2n 行,每行n个数。前n行是c,后n行是w。
输出格式:
输出计算出的最小重量,以及每个部件的供应商
三.算法描述
1.请用回溯法的方法分析“最小重量机器设计问题”
遍历顺序:从一个节点开始,以深度优先的方法搜索解空间,每一个叶子结点都代表着一个可能性,输出“重量”最小的叶子结点,并用剪枝函数避免无效的搜索。
剪枝方式:
1)约束法:以:“当前价格+该零件价格<总价格d”作为判断条件,删除不满足约束的子树。
2)限界法:以:“当前重量+该零件重量<最小重量纪录”作为判断条件,将一定不为最优解的子树删除。
1.1 说明“最小重量机器设计问题"的解空间
本题的解空间为,长度为n的供应商各种组合向量中,总价格不超过d的每个部件的供应商选择的集合所有可能的部件重量值,{(1,3,1),(1,3,2),(1,3,3)} 。
1.2 说明 “最小重量机器设计问题"的解空间树
解空间为一棵m叉树,共有n层,每一层分别表示需要一个零件,每一个节点的m个分支表示对于每个零件都有m个供应商可选择。
1.3 在遍历解空间树的过程中,每个结点的状态值是什么
间为一该路径上从第一个节点到该节点的当前总价值cv,和当前总重量cw。
#include<iostream> using namespace std; int n,m,d; int c[999][999],w[999][999]; int cw=0,cp=0;//记录该分支最小的重量和价值 int minw=999; int x[999];//保存当前重量下每个部件供应商的号码 int minx[999]; void backtrack(int i) { //遍历到了子叶 if(i>n) { if(cp<=d&&cw<minw) { minw=cw; for(int j=1; j<=n; j++) { minx[j]=x[j]; } } } else { for(int j=1; j<=m; j++) { x[i]=j;//记录下当前部件是哪一个供应商 cw=cw+w[i][j]; cp=cp+c[i][j]; if(cp<=d&&cw<minw) { backtrack(i+1); } //回溯 cw=cw-w[i][j]; cp=cp-c[i][j]; } } } int main() { //n个组件 m个供应商 总价格不超过d cin>>n>>m>>d; //第i个零件在第j个产家的价钱 for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) cin>>c[i][j]; //第i个零件在第j个产家的重量 for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) cin>>w[i][j]; //从第一个零件开始遍历 backtrack(1); //输出 cout<<minw<<endl; for(int i=1; i<=n; i++) cout<<minx[i]<<" "; return 0; }
四.对回溯法的理解
回溯法是一个采用深度优先的策略,从根节点开始进行深度遍历,先判断该节点是否包含问题的解。如果不包含,则跳过对以该节点为根的子树的搜索,回溯到其它祖先节点,直到所有子树都被遍历完成,但如果不进行有效的剪枝的话,解空间是非常庞大的,所以我们在平时一定要用约束法和限界法进行有效的剪枝,以节省时间和空间上的开销。