首先什么是电路布线问题呢?电路布线问题是类似于迷宫的问题,也是一个模拟矩阵,迷宫是每个点有8个方向可以走,但是在电路布线问题中每个点上只有上下左右4个方向可走。因为电路布线不允许对角线上布线,并且电路布线问题要求线路所走过的路程必须是最短的,即从出发点到目的点路径很可能有很多,要找的是经过跳数最少的那个。也就是说不能太多的弯儿,能直走的就直着走。
迷宫问题是只要找到出路,不管路径是如何的。在寻找通路阶段和走迷宫是差不多的,迷宫是将走过的路存储在栈中,通过试探与回溯的方法一步一步的往前行。此问题不能用栈来做了,而是用队列来辅助实现,因为要将所有的可行的点都走一遍,并把所有可行点距离出发点的路径值也要表示出来,根据这个路径值来找出最短的路径来。
使用一个矩阵来表示一个算是迷宫的东西,用0来表示可通过,用1表示不可通过。下面是模拟矩阵:
1 1 1 1 1 1 1 1
1 0 0 1 0 0 0 1
1 1 0 0 0 1 0 1
1 0 1 1 0 0 0 1
1 0 0 0 1 1 0 1
1 0 1 1 1 0 0 1
1 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1
起点是:(1,1),目的点是(6,3)。
使用结构体来表示每一个点周边可行的路线,这是一个包含行和列值的结构体,Position(row,col)。而且每个点都是四个方向,这其中有的可行有的不可行,将其存储在一个数组中Position offset[offset_num];
以下是数组中不同的元素所代表的不同方向:
row col direc
-1 0 0 上
0 1 1 右
1 0 2 下
0 -1 3 左
下面是Position 类的定义:
- #pragma once
- #include<iostream>
- using namespace std;
- class Position
- {
- public:
- int row;//矩阵 行
- int col;//矩阵 列
- public:
- Position();
- Position(int r,int c);
- ~Position();
- bool operator== (Position &P);
- void operator= (Position &P);
- friend ostream& operator<< (ostream& output,Position &P);
- friend istream& operator>> (istream& input,Position &P);
- };
- #include"position.h"
- #include<iostream>
- using namespace std;
- Position::Position()
- {}
- Position::Position(int r,int c)
- {
- row = r;
- col = c;
- }
- Position::~Position()
- {}
- bool Position::operator== (Position &P)
- {
- return ((row == P.row && col == P.col) ? true : false);
- }
- void Position::operator= (Position &P)
- {
- row = P.row;
- col = P.col;
- }
- ostream& operator<< (ostream& output,Position &P)
- {
- output<<"("<<P.row<<","<<P.col<<")" ;
- return output;
- }
- istream& operator>> (istream& input,Position &P)
- {
- input>>P.row>>P.col ;
- return input;
- }
- #pragma once
- #include"position.h"
- #include"L_Queue.h"
- //以下参数配置在头文件中会更好,在这里不做麻烦了。
- const int offset_num = 4;
- const int total_row = 8;//模拟矩阵的总行数
- const int total_col = 8;//列数
- const int start_row = 1;//起始行值
- const int start_col = 1;//起始列值
- const int finish_row = 6;//终止行值 此为数组下标值所以最大为total_row-1
- const int finish_col = 3;//终止列值最大为total_col-1
- //const Position start(start_row,start_col);//起始位置
- //const Position finish(finish_row,finish_col);//终止位置
- class DB//电路布线
- {
- private:
- Position offset[offset_num];//四个移动方向
- int grid[total_row][total_col];//一个模拟方格的矩阵
- Position here;//当前矩阵位置
- Position neighbour;//当前矩阵的可能的邻居位置
- Position start;//布线开始位置
- Position finish;//布线结束位置
- Position *path;//存储的最短路径动态数组
- int path_length;//最短路径步数
- Queue<Position> qu_pos;//装载位置的队列 靠此遍历方格
- bool FindPath();//封装 寻求路径算法
- public:
- DB();
- ~DB();
- void output();//对外 调用接口
- };
- #include"电路布线.h"
- #include<iostream>
- #include<fstream>
- using namespace std;
- //初始化 一些数据
- DB::DB()
- {
- ifstream in_grid("GRID.txt");
- for(int r=0;r<total_row;r++)
- {
- for(int c=0;c<total_col;c++)
- in_grid>>grid[r][c];
- }
- in_grid.close();
- offset[0].row = 0;offset[0].col = 1;//右
- offset[1].row = 1;offset[1].col = 0;//下
- offset[2].row = 0;offset[2].col = -1;//左
- offset[3].row = -1;offset[3].col = 0;//上
- start.row = start_row;start.col = start_col;//布线开始
- finish.row = finish_row;finish.col = finish_col;//结束
- }
- DB::~DB()
- {}
- void DB::output()
- {
- for(int r=0;r<total_row;r++)
- {
- for(int c=0;c<total_col;c++)
- cout<<grid[r][c]<<" ";
- cout<<endl;
- }
- cout<<start.row<<" "
- <<start.col<<endl;
- cout<<finish.row<<" "<<finish.col<<endl;
- cout<<endl<<endl;
- if(FindPath())
- {
- for(int i=0;i<path_length;i++)
- //cout<<path[i].row<<" "<<path[i].col<<endl;
- cout<<path[i]<<endl;
- }
- for(int r=0;r<total_row;r++)
- {
- for(int c=0;c<total_col;c++)
- cout<<grid[r][c]<<" ";
- cout<<endl;
- }
- cout<<"路径步数:"<<path_length<<endl;
- }
- //布线 算法
- bool DB::FindPath()
- {
- if(finish == start)
- {
- path_length = 0;//路径步数 为0
- return true;//返回真
- }
- here.row = start.row; here.col = start.col;//把开始位置 标记为当前位置
- grid[start.row][start.col] = 2;//把开始位置 定为2 因为矩阵中0表示通路1表示堵塞
- while(true)//靠此 无限循环把整个矩阵都赋上路径值 如果可以的情况下
- {
- for(int i=0;i<offset_num;i++)//此循环 为了把当前的四个邻居中的可以的位置都进队列
- {
- neighbour.row = here.row + offset[i].row;
- neighbour.col = here.col + offset[i].col;//试探下一个位置
- if(grid[neighbour.row][neighbour.col] == 0)//该试探位置可行
- {
- grid[neighbour.row][neighbour.col] = grid[here.row][here.col] +1;//路径值 +1
- if(neighbour.row == finish.row && neighbour.col == finish.col)//该试探是结束位置
- break;
- qu_pos.In_Queue(neighbour);//把试探位置进队列
- }
- }//if条件右括号
- //第一个break之后 再次判断是否到达finish
- if(neighbour.row == finish.row && neighbour.col == finish.col)
- break;
- if(qu_pos.isEmpty() == true)
- return false;//如果第一次四次循环之后还是队列无元素 则说明无法到达布线终点
- here = qu_pos.De_Queue();//把试探成功后进队列的元素取出赋给了当前的here
- }//while循环右括号
- //跳出大循环之后 构造路径
- path_length = grid[neighbour.row][neighbour.col] - 2;//实际的路径长度(因为之前在起始位置 有+2)
- path = new Position[path_length];//动态开辟路径长度空间
- here = finish;//把终点赋给当前值 开始反向寻找最小路径
- for(int j=path_length-1;j>=0;j--)
- {
- path[j] = here;//记下当前位置
- for(int i=0;i<offset_num;i++)
- {
- neighbour.row =here.row + offset[i].row;
- neighbour.col = here.col + offset[i].col;//到达 临近位置
- if(grid[neighbour.row][neighbour.col] == j+2)
- break;
- }//内层for循环右括号
- here = neighbour;
- }//外层for循环右括号
- return true;
- }