布线问题分支界限法求解

问题描述

印刷电路板将布线区域划分成n*m个方格阵列,精确的电路布线问题要求确定连接方格a的中点到方格b的中点的最短布线问题。在布线时,电路只能沿着直线或直角布线。为了避免线路相交,已布了线的方格做了封锁标记,其他线路不允许穿过被封锁的方格

在这里插入图片描述

问题分析

布线问题的解空间是一个图结构。
解决的思路采用分支限界法,从起始节点开始不断扩展,直到目的节点结束,得到最短的路径长度(即最优值);然后从目的节点往回回溯,逐步求得最优解。

解题步骤

  • 创建一个表示节点的结构体Position,其包含两个int变量,x,y分别表示当前节点所在的行数,列数;
  • 创建一个二维数组grid[][],表示当前的电路板,初始时,grid[i][j]=0表示可以布线,grid[i][j]=1表示该节点被封锁,不能布线。为了便于处理方格边界的问题,约定在原有的方格阵列四周增设一道围墙,这些附加方格全部标记为1,不允许扩展。
  • 创建一个队列Q,用来扩展活结点表,初始时队列为空,将起始节点的四周的可扩展节点全部加入队列,不断循环,求解最优值,直到队列为空为止。本题采用队列式分支限界法求解;
  • 创建位移矩阵offset[][],表示当前节点向上下左右扩展的相对位移
    在这里插入图片描述

输入

输入共有n+3行
第一行包括两个数,n,m表示电路板是一个n*m的方格阵列
第二行包括两个数,row1,col1,表示起始点的行号和列号
第三行包括两个数,row2,col2,表示目标点的行号和列号
然后输入n行,每行m个数,0或1,表示电路板的封锁情况

数据规模:
0<=m<=100
0<=n<=100

输出

输出只有一行
表示从起始点到目的点的最短距离

样例输入

7 7
3 2
4 6
0 0 1 0 0 0 0
0 0 1 1 0 0 0
0 0 0 0 1 0 0
0 0 0 1 1 0 0
1 0 0 0 1 0 0
1 1 1 0 0 0 0
1 1 1 0 0 0 0

样例输出

9
在这里插入图片描述

代码

#include <iostream>
using namespace std;
#include<stdio.h>
#include<stdlib.h>
#include<cstring>
#include<math.h>
#include<queue>
//方格结构体
typedef struct
{
    int x;//x表示小方格所在行号
    int y;//y表示小方格所在列号
}Position;

int grid[102][102];//用来表示电路板
int n,m;//n表示电路板行数,m表示电路板的列数
bool FindPath(Position start,Position finish,int PathLen)
{
    //起点和目的点是同一个点,最短路径为0
    if(start.x==finish.x&&start.y==finish.y){
        PathLen=0;
        return true;
    }
    //设置方格围墙,扩充边界
    for(int j=0;j<=m+1;j++)
        grid[0][j]=1;//第0行全部置1
    for(int i=0;i<=n+1;i++)
        grid[i][0]=1;//第0列全部置1
    for(int j=0;j<=m+1;j++)
        grid[n+1][j]=1;//第n+1行全部置1
    for(int i=0;i<=n+1;i++)
        grid[i][m+1]=1;//第m+1列全部置1

    //初始化相对位移,上,下,左,右
    Position offset[4];
    offset[0].x=0;offset[0].y=1;//表示向右走一格
    offset[1].x=1;offset[1].y=0;//表示向下走一格
    offset[2].x=0;offset[2].y=-1;//表示向左走一格
    offset[3].x=-1;offset[3].y=0;//表示向上走一格
    int NumOfNbrs=4;//可扩展的点为四连通区域
    Position now,nerb;//now表示当前的活结点,nerb表示与活结点相邻的上下左右四个方格
    now=start;//给now赋初值,从初始节点开始,注意start不在活结点表里面
    grid[start.x][start.y]=0;//初始节点到初始节点的
    //构建活结点表的队列
    queue<Position>Q;
    while(1){
        for(int i=0;i<NumOfNbrs;i++){
            nerb.x=now.x+offset[i].x;
            nerb.y=now.y+offset[i].y;
            //说明当前节点可以扩展,那么填充并加入活结点表
            if(grid[nerb.x][nerb.y]==0){
                grid[nerb.x][nerb.y]=grid[now.x][now.y]+1;
                //如果是目的节点,退出
                if(nerb.x==finish.x&&nerb.y==finish.y)
                    break;
                Q.push(nerb);//将新扩展的节点加入活节点表
            }
        }
        if(nerb.x==finish.x&&nerb.y==finish.y)
            break;//如果是目的节点,退出
        if(Q.empty())  return false;//当队列为空时,退出
        now=Q.front();//更新now的值,不然没法接着遍历新的活结点
        Q.pop();//将这个节点从活结点表中删除
    }
    return true;//返回
}
int main()
{
    cin>>n>>m;//输入电路板的行数,列数
    Position start,finish;//表征起始方格,目的方格
    cin>>start.x>>start.y;
    cin>>finish.x>>finish.y;
    //根据输入初始化电路板grid
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
        cin>>grid[i][j];
    int Pathlen;//用来传递参数,当路径不为0时,不用Pathlen
    //执行FindPath函数,更新grid数组,并判断路径是否为0
    FindPath(start,finish,Pathlen);
    //输出结果
    if(Pathlen==0)
        cout<<0;
    else
        cout<<grid[finish.x][finish.y];
    return 0;
}

运行结果

在这里插入图片描述

发布了97 篇原创文章 · 获赞 101 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/practical_sharp/article/details/102760949