0039算法笔记——【分支限界法】电路板排列问题
来源:互联网 发布:怎么查看淘宝销量 编辑:程序博客网 时间:2024/05/05 12:44
问题描述
将n块电路板以最佳排列方式插入带有n个插槽的机箱中。n块电路板的不同排列方式对应于不同的电路板插入方案。设B={1, 2, …, n}是n块电路板的集合,L={N1, N2, …, Nm}是连接这n块电路板中若干电路板的m个连接块。Ni是B的一个子集,且Ni中的电路板用同一条导线连接在一起。设x表示n块电路板的一个排列,即在机箱的第i个插槽中插入的电路板编号是x[i]。x所确定的电路板排列Density (x)密度定义为跨越相邻电路板插槽的最大连线数。
例:如图,设n=8, m=5,给定n块电路板及其m个连接块:B={1, 2, 3, 4, 5, 6, 7, 8},N1={4, 5, 6},N2={2, 3},N3={1, 3},N4={3, 6},N5={7, 8};其中两个可能的排列如图所示,则该电路板排列的密度分别是2,3。
左上图中,跨越插槽2和3,4和5,以及插槽5和6的连线数均为2。插槽6和7之间无跨越连线。其余插槽之间只有1条跨越连线。在设计机箱时,插槽一侧的布线间隙由电路板的排列的密度确定。因此,电路板排列问题要求对于给定的电路板连接条件(连接块),确定电路板的最佳排列,使其具有最小密度。
算法思路
电路板排列问题的解空间是一颗排列树。采用优先队列式分支限界法找出所给电路板的最小密度布局。算法中采用最小堆表示活节点优先级队列。最小堆中元素类型是BoradNode,每一个BoardNode类型的节点包含域x,表示节点所相应的电路板排列;s表示该节点已确定的电路板排列x[1:s];cd表示当前密度,now[j]表示x[1:s]中所含连接块j中的电路板数。
算法开始时,将排列树的根结点置为当前扩展结点。在do-while循环体内算法依次从活结点优先队列中取出具有最小cd值的结点作为当前扩展结点,并加以扩展。算法将当前扩展节点分两种情形处理:
1)首先考虑s=n-1的情形,当前扩展结点是排列树中的一个叶结点的父结点。x表示相应于该叶结点的电路板排列。计算出与x相应的密度并在必要时更新当前最优值和相应的当前最优解。
2)当s<n-1时,算法依次产生当前扩展结点的所有儿子结点。对于当前扩展结点的每一个儿子结点node,计算出其相应的密度node.cd。当node.cd<bestd时,将该儿子结点N插入到活结点优先队列中。
算法具体实现如下:
1、MinHeap2.h
#include <iostream>template<class Type>class Graph;template<class T> class MinHeap { template<class Type>friend class Graph;public: MinHeap(int maxheapsize = 10); ~MinHeap(){delete []heap;} int Size() const{return currentsize;} T Max(){if(currentsize) return heap[1];} MinHeap<T>& Insert(const T& x); MinHeap<T>& DeleteMin(T &x); void Initialize(T x[], int size, int ArraySize); void Deactivate(); void output(T a[],int n);private: int currentsize, maxsize; T *heap; }; template <class T> void MinHeap<T>::output(T a[],int n) { for(int i = 1; i <= n; i++) cout << a[i] << " "; cout << endl; } template <class T> MinHeap<T>::MinHeap(int maxheapsize) { maxsize = maxheapsize; heap = new T[maxsize + 1]; currentsize = 0; } template<class T> MinHeap<T>& MinHeap<T>::Insert(const T& x) { if(currentsize == maxsize) { return *this; } int i = ++currentsize; while(i != 1 && x < heap[i/2]) { heap[i] = heap[i/2]; i /= 2; } heap[i] = x; return *this; } template<class T> MinHeap<T>& MinHeap<T>::DeleteMin(T& x) { if(currentsize == 0) { cout<<"Empty heap!"<<endl; return *this; } x = heap[1]; T y = heap[currentsize--]; int i = 1, ci = 2; while(ci <= currentsize) { if(ci < currentsize && heap[ci] > heap[ci + 1]) { ci++; } if(y <= heap[ci]) { break; } heap[i] = heap[ci]; i = ci; ci *= 2; } heap[i] = y; return *this; } template<class T> void MinHeap<T>::Initialize(T x[], int size, int ArraySize) { delete []heap; heap = x; currentsize = size; maxsize = ArraySize; for(int i = currentsize / 2; i >= 1; i--) { T y = heap[i]; int c = 2 * i; while(c <= currentsize) { if(c < currentsize && heap[c] > heap[c + 1]) c++; if(y <= heap[c]) break; heap[c / 2] = heap[c]; c *= 2; } heap[c / 2] = y; } } template<class T> void MinHeap<T>::Deactivate() { heap = 0; }2、6d8.cpp
//电路板排列问题 优先队列分支限界法求解 #include "stdafx.h"#include "MinHeap2.h"#include <iostream>#include <fstream> using namespace std;ifstream fin("6d8.txt"); class BoardNode{friend int BBArrangement(int **,int,int,int *&);public:operator int() const{return cd;}private:int *x,//x[1:n]记录电路板排列s,//x[1:s]是当前节点所相应的部分排列cd,//x[1:s]的密度*now;//now[j]是x[1:s]所含连接块j中电路板数};int BBArrangement(int **B,int n,int m,int *&bestx);int main(){int m = 5,n = 8;int *bestx;//B={1,2,3,4,5,6,7,8}//N1={4,5,6},N2={2,3},N3={1,3},N4={3,6},N5={7,8}cout<<"m="<<m<<",n="<<n<<endl;cout<<"N1={4,5,6},N2={2,3},N3={1,3},N4={3,6},N5={7,8}"<<endl;cout<<"二维数组B如下:"<<endl;//构造Bint **B = new int*[n+1];for(int i=1; i<=n; i++){B[i] = new int[m+1];}for(int i=1; i<=n; i++){for(int j=1; j<=m ;j++){fin>>B[i][j];cout<<B[i][j]<<" ";}cout<<endl;}cout<<"当前最优密度为:"<<BBArrangement(B,n,m,bestx)<<endl;cout<<"最优排列为:"<<endl;for(int i=1; i<=n; i++){cout<<bestx[i]<<" ";}cout<<endl;for(int i=1; i<=n; i++){delete[] B[i];}delete[] B;return 0;}//解电路板排列问题的优先队列式分支限界法int BBArrangement(int **B,int n,int m,int *&bestx){MinHeap<BoardNode> H(1000);//活节点最小堆BoardNode E;E.x = new int[n+1];E.s = 0;E.cd = 0;E.now = new int[m+1];int *total = new int[m+1];//now[i] = x[1:s]所含连接块i中电路板数//total[i] = 连接块i中的电路板数for(int i=1; i<=m; i++){total[i] = 0;E.now[i] = 0;}for(int i=1; i<=n; i++){E.x[i] = i;//初始排列为1,2,3……nfor(int j=1;j<=m;j++){total[j] += B[i][j];//连接块中电路板数}}int bestd = m + 1;bestx = 0;do//节点扩展{if(E.s == n-1)//仅一个儿子节点{int ld = 0;//最后一块电路板的密度for(int j=1; j<=m; j++){ld += B[E.x[n]][j];}if(ld<bestd)//密度更小的电路排列{delete[] bestx;bestx = E.x;bestd = max(ld,E.cd);}else{delete []E.x;}delete []E.now;}else//产生当前扩展节点的所有儿子节点{for(int i=E.s+1;i<=n;i++){BoardNode N;N.now = new int[m+1];for(int j=1; j<=m; j++){//新插入的电路板N.now[j] = E.now[j] + B[E.x[i]][j];}int ld = 0;//新插入的电路板密度for(int j=1; j<=m; j++){if(N.now[j]>0 && total[j]!=N.now[j]){ld++;}}N.cd = max(ld,E.cd);if(N.cd<bestd)//可能产生更好的叶子节点{N.x = new int[n+1];N.s = E.s + 1;for(int j=1;j<=n;j++){N.x[j] = E.x[j];}N.x[N.s] = E.x[i];N.x[i] = E.x[N.s];H.Insert(N);}else{delete []N.now;}}delete []E.x;}//完成当前节点扩展if(H.Size() == 0){return bestd;//无扩展节点}H.DeleteMin(E);}while(E.cd<bestd);//释放做小堆中所有节点do{delete []E.x;delete []E.now;if(H.Size() == 0){break;}H.DeleteMin(E);}while(true);return bestd;}程序运行结果如图:
- 0039算法笔记——【分支限界法】电路板排列问题
- 0039算法笔记——【分支限界法】电路板排列问题
- 算法java实现--分支限界法--电路板排线问题
- 0033算法笔记——【分支限界法】分支限界法与单源最短路径问题
- 0033算法笔记——【分支限界法】分支限界法与单源最短路径问题
- 0035算法笔记——【分支限界法】布线问题
- 0035算法笔记——【分支限界法】布线问题
- 电路板排列问题分支限界解法(python)
- 0032算法笔记——【回溯法】电路板排列问题和连续邮资问题
- 0032算法笔记——【回溯法】电路板排列问题和连续邮资问题
- 算法学习笔记——分支限界法
- 0034算法笔记——【分支限界法】最优装载问题
- 0036算法笔记——【分支限界法】0-1背包问题
- 0037算法笔记——【分支限界法】最大团问题
- 0038算法笔记——【分支限界法】旅行员售货问题
- 0040算法笔记——【分支限界法】批处理作业调度问题
- 0034算法笔记——【分支限界法】最优装载问题
- 0036算法笔记——【分支限界法】0-1背包问题
- 不能继承内置数据类型
- JSON与JAVA数据的转换
- 排序
- 继承类
- 经典回顾——2012年度最佳网页设计作品出炉【上篇】
- 0039算法笔记——【分支限界法】电路板排列问题
- 第十一周 项目四:定义点类,派生园类,圆柱体类
- #pragma once的使用
- 第十一周—2.点类定义升级
- 十大外贸交易平台
- javaweb页面伪静态
- 免费字体大宝库:16款燃烧的火焰效果英文字体
- ant或者说wsadmin远程部署websphere异常
- Linux中find常见用法示例