最小电路板长度排列问题

本次实验,我选择课本P156页5-2作为实验报告。

(1) 首先是问题描述:

最小长度电路板排列问题是大规模电子系统设计中提出的实际问题。该问题的提法是,将n块电路板以最佳排列方案插入带有n个插槽的机箱中。n块电路板的不同的排列方式对应于不同的电路板插入方案。

设B={1,2,…,n }是n块电路板的集合。集合L={ N1,N2,…,Nm }是n块电路 板的m个连接块。其中每个连接块Ni是B的一个子集,且Ni中的电路板用同一根导线连 接在一起。

例如,设n=8,m=5。给定n块电路板及其m个连接块如下:

B={1,2,3,4,5,6,7,8};L={ N1,N2,N3,N4,N5};

N1={4,5,6}; N2={2,3}; N3 ={1,3}; N4={3,6}; N5 ={7,8}。

这8块电路板的一个可能的排列如图所示。

在这里插入图片描述在这里插入图片描述

则该电路板排列的密度分别是2,3。

左上图中,跨越插槽2和3,4和5,以及插槽5和6的连线数均为2。插槽6和7之间无跨越连线。其余插槽之间只有1条跨越连线。在设计机箱时,插槽一侧的布线间隙由电路板的排列的密度确定。因此,电路板排列问题要求对于给定的电路板连接条件(连接块),确定电路板的最佳排列,使其具有最小密度。

(2) 问题分析

电路板排列问题是NP难问题,因此不大可能找到解此问题的多项式时间算法。考虑采用回溯法系统的搜索问题解空间的排列树,找出电路板的最佳排列。排列树问题。对所有的电路板进行全排列,每次找到连接块的最左和最右电路板,相减得到连接块的长度,在全排列的过程中找到最小长度。

(3) 代码描述

//最小电路板排列问题
#include<iostream>
using namespace std;
const int maxn = 10000;
int originalxu[maxn];//保留初始排序
int finalxu[maxn];//保留处理后的排序
int n;//讲变量n分配到全局,方便后续的使用
int min_len=INT32_MAX; //存储最终的最短的长度
int temp_len ;//题目中临时用到的长度
int e_sum[maxn][maxn];
int m;
void traceback(int t)//构造回溯函数
{
    int left,right;//定义一个左右节点。
    int temp;//@to_do 在后续的交换操作中会用到;
    if(t==n)
    {
        temp_len=0;//在此处赋予临时变量的值为0,如果此函数内部不赋值temp_len可能会导致全局失效。
        for(int i=0;i<m;i++)//从连接块开始遍历
        {
            for(int j=0;j<n;j++)//接着进行电路板的遍历
            {
                if(e_sum[originalxu[j]][i]==1)//左边的孩子
                {
                    left = j;//TODO j和i的顺序不要搞反了;注意这个地方
                    break;
                }
            }
            for(int j=n-1;j>=0;j--)
            {
                if(e_sum[originalxu[j]][i]==1)//右边的孩子
                {
                    right = j;
                    break;
                }
            }
            if(temp_len<right-left)
            {
                temp_len = right-left;//记录最大长度;
            }
        }

        if(temp_len<min_len) {
            min_len = temp_len; //记录最大长度
            for(int i=0;i<n;i++) {
                finalxu[i] = originalxu[i];//把顺序付给新的变量;
            }
        }

    }
    for(int i=t;i<n;i++)
    {
        temp = originalxu[i];
        originalxu[i]=originalxu[t];
        originalxu[t]=temp;
        traceback(t+1);
        temp = originalxu[i];
        originalxu[i]=originalxu[t];
        originalxu[t]=temp;
    }

}

int main()
{
    cin>>n>>m;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            cin>>e_sum[i][j]; //不妨先把变量传递进来
        }
    }
    for(int t=0;t<n;t++){
        originalxu[t] = t;
    }
    traceback(0);
    cout<<min_len<<endl;
    for(int r=0;r<n;r++)
    {
        cout<<finalxu[r]+1<<" ";
    }
    cout<<endl;

(四) 总结
在写代码的时候,由于不能很好地给比变量进行命名导致某些地方可能一直出错,此外,要理清各个函数之间的关系,不能混淆了i和j,另外临时变量和全局变量一定要搞清楚,有时候在函数内部赋予局部变量会出现一些莫名其妙的bug。
顺便总结一下回溯的模板:

void backtracking(参数) {
    if (终止条件) {
        存放结果;
        return;
    }
    for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
        处理节点;
        backtracking(路径,选择列表); // 递归
        回溯,撤销处理结果
    }
}

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

savkACUNCB: IOnjn

欢迎来到我的世界

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值