假期 2020.01.23
题目描述
在实际工程中,铺设电缆等设施时,既考虑障碍物的问题,又要考虑造价最低。随着电 干设备的普及,工程中需要大量的电路板。每个电路板上有很多线路,我们在设计电路时, 尽可能地节约成本,如果一个电路板省下一分钱,也将是一笔很大的财富。布线问题就是在 m * n的方格阵列中,指定一个方格的中点a,另一个方格的中点b,问题要求找出a到b的 最短布线方案。布线时只能沿直线或直角,不能走斜线。为了避免线路相交,已布过线的方 格做了封锁标记(灰色),其他线路不允许穿过被封锁的方格。(来源《趣学算法》
算法分析
- 问题归结于寻找最短路径问题,此处采用分支界限法,借助BFS算法实现;
- 存储结构map[ ][ ]记录电路板上的位置关系,short_dist记录最优距离,choice数组记录每一次选择的最优坐标号;
int map[Max_size][Max_size];//地图
int shortest_dist;//最优值
struct Position {
int x;
int y;
};//位置
Position* choice;
- 由于在方格中的每一个位置,最多有4个方向的移动,上下左右,因此设置方向数组,便于表示
Position direction[4], here, next;//方向数组,当前格,下一格
direction[0].x = 0;//下
direction[0].y = 1;
direction[1].x = 1;//右
direction[1].y = 0;
direction[2].x = 0;//上
direction[2].y = -1;
direction[3].x = -1;//左
direction[3].y = 0;
- 因为采用bfs算法实现,那么需要设置队列存储每次的处理结构
queue<Position> q;//创建队列
- 将每一步可执行方案放入队列中
for (int i = 0; i <= 3; i++)
{
next.x = here.x + direction[i].x;
next.y = here.y + direction[i].y;
if (map[next.x][next.y] == -1)//未布线
{
map[next.x][next.y] = map[here.x][here.y] + 1;
q.push(next);//入队列
}
if (next.x == end_point.x && next.y == end_point.y)//到达目的地
break;
}
- 然后出队首元素,并且重复第5步骤,直到找到最优解
- 由于此处实现采用,每占用一个位置,此位置的编号基于前者加一,那么输出最优解时,遍历找到比当前编号小1的元素位置即是最优方案的一个途径点
choice = new Position[shortest_dist];//创建对象
here = end_point;
for (int i = shortest_dist - 1; i >= 0; i--)
{
choice[i] = here;
for (int j = 0; j <= 3; j++)
{
next.x = here.x + direction[j].x;
next.y = here.y + direction[j].y;
if (map[next.x][next.y] == i)
break;
}
here = next;
}
代码解析
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
constexpr auto Max_size = 100;
int map[Max_size][Max_size];//地图
int shortest_dist;//最优值
struct Position {
int x;
int y;
};//位置
Position* choice;
int find_path(Position start_point,Position end_point);//查找函数
int main()
{
Position start_point,end_point;
int i, j, map_row, map_line, obstacle,v,w;
cout << "请输入方阵的大小(行数与列数,空格分开):";
cin >> map_row>>map_line;
cout << "请输入障碍物的数目:";
cin >> obstacle;
cout << "请输入障碍物的坐标:" << endl;
for (i = 1; i <= map_row; i++)
for (j = 1; j <= map_line; j++)
map[i][j] = -1;
for (i = 0; i <= map_line + 1; i++)
map[0][i] = map[map_row + 1][i] = -2;
for (i = 0; i <= map_row + 1; i++)
map[i][0] = map[i][map_line + 1 ] -2;
for (i = 1; i <= obstacle; i++){
cin >> v >> w;
map[v][w] = -2;
}
cout << "请输入起始点坐标:";
cin >> start_point.x >> start_point.y;
cout << "请输入目的点坐标:";
cin >> end_point.x >> end_point.y;
if (find_path(start_point,end_point))
{
cout << "最短长度是:" << shortest_dist << endl;
cout << "最优方案是:" << endl;
for (int i = 0; i <= shortest_dist - 1; i++)
cout<<"第"<<i + 1<< "点 坐标:x = " << choice[i].x << "坐标:y = " << choice[i].y << endl;
}
else
cout << "任务无法完成" << endl;
return 0;
}
int find_path(Position start_point,Position end_point)
{
if (start_point.x == end_point.x && end_point.y == start_point.y){//目的地与起点是同一个坐标
shortest_dist = 0;
return 1;
}
Position direction[4], here, next;//方向数组,当前格,下一格
direction[0].x = 0;//下
direction[0].y = 1;
direction[1].x = 0;//上
direction[1].y = -1;
direction[2].x = 1;//右
direction[2].y = 0;
direction[3].x = -1;//左
direction[3].y = 0;
here = start_point;
map[start_point.x][start_point.y] = 0;//初始化0,-1表示未布线,-2表示墙壁
queue<Position> q;//创建队列
while (1) {
for (int i = 0; i <= 3; i++)//每次四个方向的选择
{
next.x = here.x + direction[i].x;
next.y = here.y + direction[i].y;
if (map[next.x][next.y] == -1)//未布线
{
map[next.x][next.y] = map[here.x][here.y] + 1;
q.push(next);//入队列
}
if (next.x == end_point.x && next.y == end_point.y)//到达目的地
break;
}
if (next.x == end_point.x && next.y == end_point.y)//到达目的地
break;
if (q.empty())//队列为空时,证明无最优解
return 0;
else {
here = q.front();//c出队
q.pop();
}
}
shortest_dist = map[end_point.x][end_point.y];
choice = new Position[shortest_dist];//创建对象
here = end_point;
for (int i = shortest_dist - 1; i >= 0; i--)
{
choice[i] = here;
for (int j = 0; j <= 3; j++)//每次寻找比i小1的坐标
{
next.x = here.x + direction[j].x;
next.y = here.y + direction[j].y;
if (map[next.x][next.y] == i)
break;
}
here = next;
}
return 1;
}