首页 > 编程语言 >【计算机算法设计与分析】6-5 最小重量机器设计问题(C++_回溯法/分支限界法)

【计算机算法设计与分析】6-5 最小重量机器设计问题(C++_回溯法/分支限界法)

时间:2023-06-20 11:35:25浏览次数:39  
标签:11 13 12 15 int C++ 20 设计 限界


问题描述

设某一机器由 n 个部件组成,每一种部件都可以从 m 个不同的供应商处购得。设 wij 是从供应商 j 处购得的部件 i 的重量, cij 是相应的价格。
设计一个优先队列式分支限界法,给出总价格不超过 d 的最小重量机器设计。

对于给定的机器部件重量和机器部件价格,设计一个优先队列式分支限界法,计算总价格不超过 d 的最小重量机器设计。

数据输入:
第一行有 3 个正整数 n ,m 和 d。接下来的 2n 行,每行 m 个数。前 n 行是 c,后 n 行是 w。

priority_queue用法

具体用法参照:priority_queue的用法,我仅讲解此次分支限界算法中使用的优先队列。

bool operator<(const node& a) const{//小根堆(返回true,则证明前者优先级低于后者,则后者居上!)
 if (weigth!=a.weigth)
 return weigth>a.weigth;//例:倘若weigth>a.weigth为真,则a的优先级更高,即weigth小的对象优先级更高!
 else if(level!=a.level)
 return a.level<level;
 else
 return num>a.num;
 }

在写这道算法之前,我对优先队列的印象只有这两个固定的用法:

大根堆:priority_queue<int> q;
小根堆:priority_queue<int, vector<int>, greater<int>> q;

但是,如你所见,这并不能满足分支限界法中对于优先队列的需求,我们必须自己定义优先函数,即在类或结构体中重载【计算机算法设计与分析】6-5 最小重量机器设计问题(C++_回溯法/分支限界法)_i++符号。本文的优先函数规定:重量小的节点优先度最高;倘若两者重量相同,则当前零件序号高者优先级更高(因为本题分层次树状结构进行遍历,每一层的节点为当前零件的m个供应商,每层确定一种零件,因此“零件序号高者”即为靠近叶子节点者);倘若两者重量和当前遍历层数都相同,则供应商序号靠前者优先级更高。
若有疑问可留言,我会尽量及时答复。

Code(回溯法)

#include<bits/stdc++.h>
using namespace std;
int n, m, d, c[100][100], w[100][100], vis[100], ans = 0x3f3f3f, result[100];
void dfs(int cnt, int csum, int wsum) {
	if (cnt == n) {
		if (csum <= d && ans > wsum) {
			ans = wsum;
			for (int i = 0; i < n; i++)
				result[i] = vis[i];
		}
		return;
	}
	for (int i = 0; i < m; i++) {
		int t = vis[cnt];
		if (csum <= d) {//价格剪枝
			vis[cnt] = i;
			dfs(cnt + 1, csum + c[cnt][i], wsum + w[cnt][i]);
			vis[cnt] = t;
		}
	}
}
int main()
{
	cin >> n >> m >> d;
	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
			cin >> c[i][j];
	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
			cin >> w[i][j];
	dfs(0, 0, 0);
	cout << ans << endl;
	for (int i = 0; i < n; i++)
		cout << result[i] + 1 << " ";
	return 0;
}

Code(分支限界法)

#include<bits/stdc++.h>
using namespace std;

int n, m, d, min_weigth=0x3f3f3f;
int ans[100];
int c[100][100], w[100][100];
struct node{
    int weigth, cost, level, num, value[100];
    node(int a, int b, int c, int d):weigth(a), cost(b), level(c), num(d){}
    bool operator<(const node& a) const{//小根堆(返回true,则证明前者优先级低于后者,则后者居上!)
        if (weigth!=a.weigth)
            return weigth>a.weigth;//例:倘若weigth>a.weigth为true,则a的优先级更高,即weigth小的对象优先级更高!
        else if(level!=a.level)
            return a.level<level;
        else 
            return num>a.num;
    }
};
priority_queue<node> q;//小根堆
int main()
{
    cin>>n>>m>>d;
    for(int i=0;i<n;i++){//c
        for(int j=0;j<m;j++){
            cin>>c[i][j];
        }
    }
    for(int i=0;i<n;i++){//w
        for(int j=0;j<m;j++){
            cin>>w[i][j];
        }
    }
    for(int i=0;i<m;i++){//优先队列初始化
        node temp=node(w[0][i], c[0][i], 0, i);
        if(temp.cost>d)//剪枝(价格)
            continue;
        else{
            temp.value[0]=i+1;
            q.push(temp);
        }
    }
    while(!q.empty()){
        node temp=q.top();
        q.pop();
        if(temp.level<n-1){
            for(int i=0;i<m;i++){
                node t=node(temp.weigth+w[temp.level+1][i], temp.cost+c[temp.level+1][i], temp.level+1, i);
                if(t.level==n-1){//到达叶子节点
                    if(t.weigth>min_weigth||t.cost>d)//剪枝(重量and价格)
                        continue;
                    else if(t.weigth<min_weigth){
                        min_weigth=t.weigth;//最小重量更新
                        for(int i=0;i<n-1;i++){//最优路径更新
                            ans[i]=temp.value[i];
                        }
                        ans[n-1]=i+1;
                    }
                }
                if(t.level<n-1){//非叶子节点
                    if(t.cost>d){//剪枝(价格)
                        continue;
                    }
                    else{
                        for(int i=0;i<t.level;i++)//历史路径
                            t.value[i]=temp.value[i];
                        t.value[t.level]=i+1;//路径更新
                        q.push(t);
                    }
                }
            }
        }
    }
    cout<<min_weigth<<endl;
    for(int i=0;i<n;i++){
        cout<<ans[i]<<" ";
    }
    return 0;
}

测试

输入:
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

输入:
8 18 14
18 15 20 5 15 10 16 6 1 6 17 6 1 2 17 15 13 17
16 6 7 4 7 2 11 6 18 4 13 12 8 5 2 8 15 14
12 6 19 10 13 8 2 10 16 4 15 15 16 13 17 12 14 4
18 18 2 13 15 19 5 12 18 7 13 9 8 17 10 13 15 11
8 5 14 11 18 20 17 3 11 17 13 11 4 9 17 14 19 1
10 7 8 11 13 3 19 3 12 11 12 14 4 2 12 10 14 15
12 9 13 9 16 17 12 15 6 3 11 17 13 17 14 13 4 4
19 12 3 19 3 20 19 12 8 19 8 10 19 20 3 1 7 1
16 12 4 16 2 6 15 1 13 3 7 16 5 3 16 16 14 19
12 14 6 2 11 15 9 17 15 16 19 20 14 14 20 9 4 4
6 13 16 6 3 12 12 19 11 20 4 13 9 18 7 17 8 1
4 17 3 20 3 8 12 7 4 12 6 12 1 18 13 20 20 8
4 15 1 10 2 12 8 11 5 4 20 13 12 20 1 3 3 11
1 9 2 1 16 1 12 4 5 2 7 15 12 3 9 4 13 6
13 1 10 8 5 13 20 10 6 4 8 15 8 8 20 11 9 9
2 10 11 1 18 8 20 11 18 2 3 6 14 16 19 4 3 15
输出:
57
13 6 7 3 18 14 10 16


标签:11,13,12,15,int,C++,20,设计,限界
From: https://blog.51cto.com/u_16165815/6521637

相关文章

  • 【蓝桥杯_真题演练】换零钞(C++_遍历)
    题目x星球的钞票的面额只有:100元,5元,2元,1元,共4种。小明去x星旅游,他手里只有2张100元的x星币,太不方便,恰好路过x星银行就去换零钱。小明有点强迫症,他坚持要求200元换出的零钞中2元的张数刚好是1元的张数的10倍,剩下的当然都是5元面额的。银行的工作人员有点为难,你能帮助算出:在满足小......
  • 【蓝桥杯_真题演练】第九届C/C++省赛B组_C-乘积尾零(C++_数论)
    Problem如下的10行数据,每行有10个整数,请你求出它们的乘积的末尾有多少个零?56504542355447394641143871907390432927587949611356595245743230514434670435949937117368663397475975573070228714539899148657223135117040145510512072928809......
  • PTA_乙级_1015 德才论(C++_模拟_快排)
    宋代史学家司马光在《资治通鉴》中有一段著名的“德才论”:“是故才德全尽谓之圣人,才德兼亡谓之愚人,德胜才谓之君子,才胜德谓之小人。凡取人之术,苟不得圣人,君子而与之,与其得小人,不若得愚人。”现给出一批考生的德才分数,请根据司马光的理论给出录取排名。输入格式:输入第一行给出3个......
  • P3371 【模板】单源最短路径(弱化版)(C++_SPFA算法_链式向前星)
    题目背景本题测试数据为随机数据,在考试中可能会出现构造数据让SPFA不通过,如有需要请移步P4779。题目描述如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度。输入格式第一行包含三个整数n,m,s,分别表示点的个数、有向边的个数、出发点的编号。接下来m行每行包含三个......
  • CS5211:EDP转LVDS屏转接板方案芯片设计
    大多数液晶显示屏及便携屏都有LVDS接口,若是电脑或投屏设备为EDP接口的话,就需要中间做一个EDP转LVDS屏转接板。那么如何能设计一块低成本的EDP转LVDS转接板呢?了解资料CS5211是一个eDP到LVDS转换器,配置灵活,适用于低成本显示系统。CS5211总功率小于300mW,供电网络设计可以简化。下图......
  • C++ primer plus学习之第二章
    1.引用:intival=1024;int&refval=ival;//正确,refval时ival的别名int&re;//错误,引用必须被初始化int&ii=42;//错误:不能为非常量引用绑定字面值constint&ii=42;//正确:可以为常量引用绑定字面值2.初始化空指针int*p=0;int*p=NULL;int*p=nullptr;//最好用这个任何非零指......
  • 污水净化处理厂PLC自动化程序设计编程调试一套市政污水处理厂PLC自动化程序设计编程调
    污水净化处理厂PLC自动化程序设计编程调试一套市政污水处理厂PLC自动化程序设计编程调试一套含技术要求合同,上位机画面_组态王,plc程序_西门子300,触摸屏_ktp1000,电气设计图纸一套,plc点表等,此项目现场调试两个月,现正常运行中,非常适合自动化刚入行的新手学习,也适合对污水处理需要的......
  • 总结C++中#include<>和#include""的区别
    查找目录不同1、#include<>编译器直接从系统类库目录里查找头文件比如在vs中,使用#include<>编译器会直接在vs安装目录下在编译器自带的库文件中进行搜索。如果类库目录下查找失败,编译器会终止查找,直接报错:Nosuchfileordirectory.如果我们自定义一个头文件"aaa.h",将其放在......
  • Java设计模式之代理模式--经纪人的工作
    前言本文主要讲述代理模式,文中使用通俗易懂的案例,使你更好的学习本章知识点并理解原理,做到有道无术。一.什么是代理模式代理模式是23种设计模式中结构型模式的一种,它的核心是通过代理类来完成其他对象的访问,降低访问者和被访问者的耦合度,也对功能进行了增强。二.生活中的代理......
  • CCF_201912-1 报数(C++_模拟)
    思路代码可能写的有点啰嗦冗余,写的时候有点急写完一节就直接复制粘贴了蛤蛤蛤,所以导致中间有些代码比较重复。Code#include<bits/stdc++.h>//模拟usingnamespacestd;intn,sum=0,a,b,c,d;booljudge(ints){ inttemp=s; if(temp%7==0) return0; while......