分支界限法--最优工程布线

假期 2020.01.23

题目描述

在实际工程中,铺设电缆等设施时,既考虑障碍物的问题,又要考虑造价最低。随着电 干设备的普及,工程中需要大量的电路板。每个电路板上有很多线路,我们在设计电路时, 尽可能地节约成本,如果一个电路板省下一分钱,也将是一笔很大的财富。布线问题就是在 m * n的方格阵列中,指定一个方格的中点a,另一个方格的中点b,问题要求找出a到b的 最短布线方案。布线时只能沿直线或直角,不能走斜线。为了避免线路相交,已布过线的方 格做了封锁标记(灰色),其他线路不允许穿过被封锁的方格。(来源《趣学算法》


算法分析

  1. 问题归结于寻找最短路径问题,此处采用分支界限法,借助BFS算法实现;
  2. 存储结构map[ ][ ]记录电路板上的位置关系,short_dist记录最优距离,choice数组记录每一次选择的最优坐标号;
int map[Max_size][Max_size];//地图
int shortest_dist;//最优值
struct Position {
	int x;
	int y;
};//位置
Position* choice;
  1. 由于在方格中的每一个位置,最多有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;
  1. 因为采用bfs算法实现,那么需要设置队列存储每次的处理结构
queue<Position> q;//创建队列
  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;
}
  1. 然后出队首元素,并且重复第5步骤,直到找到最优解
  2. 由于此处实现采用,每占用一个位置,此位置的编号基于前者加一,那么输出最优解时,遍历找到比当前编号小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;
}

运行结果

在这里插入图片描述

发布了166 篇原创文章 · 获赞 45 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_44116998/article/details/104077421