算法分析与设计实验报告——最小重量机器设计问题

算法分析与设计实验报告——最小重量机器设计问题

一、 实验目的

掌握回溯法、分支限界法的基本思想和解决问题的基本步骤,认识回溯法和分支限界法的联系与区别。

二、实验要求

用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
 */


附件二 运行结果

回溯法

在这里插入图片描述

分支限界法

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值