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;}
    程序运行结果如图:



原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 不知道自己想要做什么工作怎么办 三星note4微信出现闪退怎么办 魅蓝note6手机自动闪退怎么办 苹果6s系统内存占用量过大怎么办 想在一年通过会计初级和中级怎么办 特殊岗位退休档察写的力工怎么办 面试时期望工资说低了。怎么办 面试时期望薪资写低了怎么办 高考后比一模差了80分怎么办 戒了烟我不习惯没有你我怎么办 没有你我不习惯没有你我怎么办 做什么都没兴趣嫌麻烦怎么办 快递还在路上就确认收货了怎么办 微信显示时间与手机不符怎么办 微信提示银行卡预留手机不符怎么办 得了湿疹后吃了海鲜严重了怎么办 看到小区街道乱扔的垃圾你会怎么办 去韩国干服务员不会讲韩语怎么办 华为手机键盘变英文字母大了怎么办 淘宝申请售后卖家余额不足怎么办 发票名称少写了一个字怎么办 微博数量与实际数量不一致怎么办 在淘宝中要买的商品卖完了怎么办 病因写错了保险不报销怎么办? 上学期间保险名字写错了怎么办 塑料盆上的商标纸撕了胶怎么办 川航买机票名字错了两个字怎么办 买机票护照号码填错了怎么办 换旅行证给孩子改名字怎么办 浦发信用卡卡片名字印错了怎么办 公主工作很辛苦坚持不下去怎么办 在表格里怎么办名字转换成拼音 激素脸有黑头毛孔大该怎么办 兢兢业业上班但不招领导喜欢怎么办 身体长的还算苗条但就屁股大怎么办 我想学英语从基础开始要怎么办 政府单位领导给我调岗我该怎么办 领导在单位想捞钱我该怎么办 单位领导是宵小之人我该怎么办 一件事想不明白非得想明白怎么办 在四楼上课时发生地震该怎么办