算法分析与设计实验报告——最小重量机器设计问题
目录:
一、 实验目的
掌握回溯法、分支限界法的基本思想和解决问题的基本步骤,认识回溯法和分支限界法的联系与区别。
二、实验要求
用c++语言实现用回溯法、分支限界法解决最小重量机器设计问题,分析时间复杂性,体会回溯法、分支限界法解决问题的基本思路和步骤。
三、 实验原理
四、 实验过程(步骤)
见附件一
实验步骤、特点
重要源代码(流操作的部分要醒目的提示并注释)
五、 运行结果
见附件二
六、实验分析与讨论
遇到的问题,及解决方案
七、实验特色与心得
附件一 实验过程(步骤)
回溯法
//回溯法
#include <bits/stdc++.h>
#define maxn 110
using namespace std;
int w[maxn][maxn];
int c[maxn][maxn];
int bestx[maxn];
int x[maxn];
int n, m, d;
int cw = 0, cc = 0, bestw = 0x3f3f3f3f;
void Backtrack(int t) {
if (t > n) {
bestw = cw;
for (int i = 1; i <= n; i++)
bestx[i] = x[i];
//return;
} else {
for (int i = 1; i <= m; i++) {
if (cc + c[t][i] <= d && cw + w[t][i] < bestw) {
x[t] = i;
cc += c[t][i];
cw += w[t][i];
Backtrack(t + 1);
cc -= c[t][i];
cw -= w[t][i];
}
}
}
}
int main() {
cout << "请依次输入部件数,供应商数,限定价格:" << endl;
cin >> n >> m >> d;
cout << "请输入各部件的在不同供应商的重量:" << endl;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
cin >> w[i][j];
cout << "请输入各部件的在不同供应商的价格:" << endl;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
cin >> c[i][j];
Backtrack(1);
cout << "最小重量为:" << bestw << endl;
cout << "每个部件的供应商:" << endl;
for (int i = 1; i <= n; i++)
cout << bestx[i] << " ";
cout << endl;
return 0;
}
/*
3 3 4
1 2 3
3 2 1
2 2 2
1 2 3
3 2 1
2 2 2
*/
分支限界法
//分支限界法
#include <bits/stdc++.h>
using namespace std;
int n; //部件数量
int m; //供应商数量
int d; //价格上限
int bestw; //最小的重量
int **c = nullptr; //二维数组,每个部件不同商家的价格
int **w = nullptr; //二维数组,每个部件不同商家的重量
//每一个部件的信息
class Node {
public:
int weight; //当前已选机器的重量和
int val; //当前已选机器的价值和
int source; //哪个供货商
int level; //第几层,也代表了第几个部件
int priority; //优先级
Node *father;
};
Node *leaf;//叶子结点
void InPut() {
cout << "请依次输入部件数,供应商数,限定价格:" << endl;
cin >> n >> m >> d;
w = new int *[n + 1];
c = new int *[n + 1];
for (int i = 1; i <= n; i++) {
w[i] = new int[m + 1];
c[i] = new int[m + 1];
}
leaf = nullptr;
cout << "请输入各个部件在各个供应商处购买的价格:" << endl;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
cin >> c[i][j];
cout << "请输入各个部件在各个供应商处购买的重量:" << endl;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
cin >> w[i][j];
}
//优化的优先级设定
bool operator<(Node a, Node b) //level按照减序
{
if (a.priority == b.priority)return a.level < b.level; //如果重量相同,选择level大的。
return a.priority > b.priority;//否则,重量小的先出队
}
//计算当前节点的优先级
void QueuePriority(Node a) {
int currentMinW;
a.priority = a.val;
//int temp_min_c = INT_MAX;
for (int i = a.level + 1; i <= n; i++)//选出剩余的部件在售货商中购买的最小质量,就是选择每一层最小的质量
{
currentMinW = INT_MAX;
for (int j = 1; j <= m; j++) //每一层找最小的
{
currentMinW = currentMinW < w[i][j] ? currentMinW : w[i][j];//从m个商家中选择当层重量最小的
}
a.priority += currentMinW;
}
}
//约束函数
bool constraint(Node *pNode, int i) {
return pNode->val + c[pNode->level + 1][i] <= d || pNode->weight + w[pNode->level + 1][i] <= bestw;
}
//创建节点
Node createNode(int level, Node *father, int source, int val, int weight) {
Node newNode{};
newNode.level = level;//层次加1
newNode.father = father;
newNode.source = source;
newNode.val = val;
newNode.weight = weight;
return newNode;
}
void MinWeightMachine() {
int i, j;
bestw = INT_MAX;
Node initial{};
initial = createNode(0, nullptr, 0, 0, 0);
QueuePriority(initial); //计算优先级
priority_queue<Node> heap; //用优先队列,建立一个最小堆。加入进去就会自动排好序的。
heap.push(initial);
while (!heap.empty()) {
Node *pNode = new Node(heap.top());
heap.pop();//队首元素作为父节点出队,即优先级值小的活结点先扩展
if (pNode->level == n)//到达叶节点,不能扩展 ,得到一个解
{
if (pNode->weight < bestw) //更新
{
bestw = pNode->weight;
//MinValue = pNode ->val;
leaf = pNode; //记录是最后是哪个结点数据,便于回溯找最优解
}
} else {
for (i = 1; i <= m; i++)//扩展结点,依次选择每个售货商,每次都是m叉树
{
//可行性剪枝和限界剪枝
if (constraint(pNode, i)) {
Node newNode{};//生儿子结点
newNode = createNode(pNode->level + 1, pNode, i, pNode->val + c[pNode->level + 1][i], pNode->weight + w[pNode->level + 1][i]);
QueuePriority(newNode); //计算优先值
heap.push(newNode);//儿子入队
}
}
}
}
}
void OutPut() {
cout << "求得的最小重量为:" << bestw << endl;
int *result = new int[n + 1];
for (int i = n; i >= 1; i--) {
result[i] = leaf->source;//从最后叶子结点回溯到根节点
leaf = leaf->father;
}
cout << "各个部件的供应商分别为:" << endl;
for (int i = 1; i <= n; i++)
cout << result[i] << " ";
cout << endl;
}
int main() {
InPut();
MinWeightMachine();
OutPut();
return 0;
}
/*
3 3 4
1 2 3
3 2 1
2 2 2
1 2 3
3 2 1
2 2 2
*/