最短路径-从dijstra到导航网格

本文对比了Dijkstra算法和A*搜索算法在求解从原点到目标点的最短路径问题中的应用场景,重点解析了A*算法的启发式性质及其在静态路网和棋盘格问题上的优势。同时,展示了两者在计算最短路径时的具体实现过程。
摘要由CSDN通过智能技术生成

dijstra算法

应用场景

从原点出发,从图上的边到达另一个点所经过的路径中,各边上权值之和最小的路径称为最短路径。

算法过程

/**
从原点0到目标点1的最短距离
算法思想:类似prim算法,定义一个一维数组(path)存储V0到某个点的最短距离
*/
int shortestPathDijStra(int N) 
{	
	//1、path 数组初始化,如果找到比原来更短的则直接覆盖
	memcpy(path, matrix[0], MAX_SIZE);
	
	visit[0] = true;
	for (int i=1;i<N;i++) 
	{
		//2、在已经存在的路径中找到一条最短的且未被访问的路径节点
		int minDis = INF;
		int minIndex = -1;
		for (int j=1;j<=N;j++) 
		{
			if (!visit[j] && minDis > path[j])
			{
				minDis = path[j];
				minIndex = j;
			}
		}
		
		if (minIndex== -1)
			break;
		
		visit[minIndex] = true;
		//3、在未被访问的路径节点中,判断是否比现在已经存在的最短路径短,是则进行覆盖
		for (int j=1;j<=N;j++) 
		{
			if (!visit[j] && path[j] > (minDis + matrix[minIndex][j])) 
			{
				path[j] = minDis + matrix[minIndex][j];
			}	
		}
	}
	return path[1];
}

oj

昂贵的聘礼

A star 算法

应用场景

A* 搜索是静态路网中求解最短路径的最有效的直接搜索方式。算法中的估算函数与实际距离越接近,最终搜索速度最快。
A* 搜索与Dijstra的不同之处在于A*是一种“启发式”搜索,它有一些我们告诉它的先验知识,对BFS的顺序进行了调整,少搜索了那些不太可能经过的点,从而能更快找到目标点的最短距离。

关于估值函数的总结

启发函数:
F = G + H

G:从起始点到当前点的实际移动代价
H:从当前点到目标点的估算成本
G来源于已知信息,H为未知信息的估算,F为选择下一个节点进行遍历的依据。

关于H的特性:

  • 在极端情况下,H 为0,则算法退化为Dijstra算法
  • H小于等于实际距离,一定能找到最短距离,H值越小,将遍历的节点越多
    证明:*定义d为实际距离,g + d (最优搜索路径) < g + d (非最优搜索距离), 若 H < d,则不会存在一种情况,使(最优搜索路径的)g + h > (非最优搜索的)g + d。随着深度的不断增加,g + h 会不断趋向 g + d。*在一个非最优解的路径中,随着深度增大,一定会在某一层,出现最优解估值大的情况,所以最先搜索到的就是最优解。
  • H大于实际距离,不保证找到最短距离,但此时算法会很快

算法过程

const int MAX_SIZE = 105;
int mp[MAX_SIZE*MAX_SIZE];
struct Knight
{
	int f, g, h;
	int x, y;
	bool operator < (const Knight b) const
	{
		return f > b.f;
	}
	Knight(int F, int G, int H) 
	{
		f = F;
		g = G;
		h = H;
	}
};
//1、定义开放列表
priority_queue<Knight> openList;
int scol, srow, ecol, erow;
int dir[][2] = {{1,-2},{1,2},{-1,-2},{-1,2},{2,-1},{2,1},{-2,-1},{-2,1}};
bool isValid(int x, int y) 
{
	return x>=0&&x<8&&y>=1&&y<=8;
}

//启发函数
int heuristic(int x, int y)
{
	return max(abs(x - ecol), abs(y - erow))/2;
}

/**3、重复如下工作:
	a)寻找开放列表中F值最低的点
	b)把它切换到关闭列表(标记)
	c)遍历它相邻的每一个点
	*/
int Astar() 
{
	while(!openList.empty()) 
	{
		Knight top = openList.top();
		openList.pop();
		
		if (top.x == ecol && top.y == erow)
		{
			return top.g;
		}
		
		mp[top.x*MAX_SIZE + top.y] = 1;
		for (int i=0; i<8; i++) 
		{
			int x = dir[i][0] + top.x;
			int y = dir[i][1] + top.y;
			if (isValid(x, y) && mp[x*MAX_SIZE + y] == 0) 
			{
				int h = heuristic(x, y);
				int g = top.g + 1;
				int f = g + h;
				Knight p(f, g, h);
				p.x = x;
				p.y = y;
				openList.push(p);
			}
		}
		
	}
	return -1;
	
}

int main()
{
	char from[20], to[20];
	while(scanf("%s", from) != EOF) 
	{
		scanf("%s", to);
		scol = from[0] - 'a';
		srow = from[1] - '0';
		ecol = to[0] - 'a';
		erow = to[1] - '0';
		int h = heuristic(scol,srow);
		int g = 0;
		int f = g + h;
		Knight start(f, g, h);
		start.x = scol;
		start.y = srow;
		
		while(!openList.empty())
			openList.pop();
		memset(mp, 0, sizeof(int)*MAX_SIZE*MAX_SIZE);
		//2、将起始点加入开放列表
		openList.push(start);
		cout<<Astar()<<endl;
	}
	return 0;
}

oj

Knight Moves最短路径-从dijstra到导航网格

dijstra算法

应用场景

从原点出发,从图上的边到达另一个点所经过的路径中,各边上权值之和最小的路径称为最短路径。

算法过程

/**
从原点0到目标点1的最短距离
算法思想:类似prim算法,定义一个一维数组(path)存储V0到某个点的最短距离
*/
int shortestPathDijStra(int N) 
{	
	//1、path 数组初始化,如果找到比原来更短的则直接覆盖
	memcpy(path, matrix[0], MAX_SIZE);
	
	visit[0] = true;
	for (int i=1;i<N;i++) 
	{
		//2、在已经存在的路径中找到一条最短的且未被访问的路径节点
		int minDis = INF;
		int minIndex = -1;
		for (int j=1;j<=N;j++) 
		{
			if (!visit[j] && minDis > path[j])
			{
				minDis = path[j];
				minIndex = j;
			}
		}
		
		if (minIndex== -1)
			break;
		
		visit[minIndex] = true;
		//3、在未被访问的路径节点中,判断是否比现在已经存在的最短路径短,是则进行覆盖
		for (int j=1;j<=N;j++) 
		{
			if (!visit[j] && path[j] > (minDis + matrix[minIndex][j])) 
			{
				path[j] = minDis + matrix[minIndex][j];
			}	
		}
	}
	return path[1];
}

oj

昂贵的聘礼

A star 算法

应用场景

A* 搜索是静态路网中求解最短路径的最有效的直接搜索方式。算法中的估算函数与实际距离越接近,最终搜索速度最快。
A* 搜索与Dijstra的不同之处在于A*是一种“启发式”搜索,它有一些我们告诉它的先验知识,对BFS的顺序进行了调整,少搜索了那些不太可能经过的点,从而能更快找到目标点的最短距离。

关于估值函数的总结

启发函数:
F = G + H

G:从起始点到当前点的实际移动代价
H:从当前点到目标点的估算成本
G来源于已知信息,H为未知信息的估算,F为选择下一个节点进行遍历的依据。

关于H的特性:

  • 在极端情况下,H 为0,则算法退化为Dijstra算法
  • H小于等于实际距离,一定能找到最短距离,H值越小,将遍历的节点越多
    证明:*定义d为实际距离,g + d (最优搜索路径) < g + d (非最优搜索距离), 若 H < d,则不会存在一种情况,使(最优搜索路径的)g + h > (非最优搜索的)g + d。随着深度的不断增加,g + h 会不断趋向 g + d。*在一个非最优解的路径中,随着深度增大,一定会在某一层,出现最优解估值大的情况,所以最先搜索到的就是最优解。
  • H大于实际距离,不保证找到最短距离,但此时算法会很快

算法过程

const int MAX_SIZE = 105;
int mp[MAX_SIZE*MAX_SIZE];
struct Knight
{
	int f, g, h;
	int x, y;
	bool operator < (const Knight b) const
	{
		return f > b.f;
	}
	Knight(int F, int G, int H) 
	{
		f = F;
		g = G;
		h = H;
	}
};
//1、定义开放列表
priority_queue<Knight> openList;
int scol, srow, ecol, erow;
int dir[][2] = {{1,-2},{1,2},{-1,-2},{-1,2},{2,-1},{2,1},{-2,-1},{-2,1}};
bool isValid(int x, int y) 
{
	return x>=0&&x<8&&y>=1&&y<=8;
}

//启发函数
int heuristic(int x, int y)
{
	return max(abs(x - ecol), abs(y - erow))/2;
}

/**3、重复如下工作:
	a)寻找开放列表中F值最低的点
	b)把它切换到关闭列表(标记)
	c)遍历它相邻的每一个点
	*/
int Astar() 
{
	while(!openList.empty()) 
	{
		Knight top = openList.top();
		openList.pop();
		
		if (top.x == ecol && top.y == erow)
		{
			return top.g;
		}
		
		mp[top.x*MAX_SIZE + top.y] = 1;
		for (int i=0; i<8; i++) 
		{
			int x = dir[i][0] + top.x;
			int y = dir[i][1] + top.y;
			if (isValid(x, y) && mp[x*MAX_SIZE + y] == 0) 
			{
				int h = heuristic(x, y);
				int g = top.g + 1;
				int f = g + h;
				Knight p(f, g, h);
				p.x = x;
				p.y = y;
				openList.push(p);
			}
		}
		
	}
	return -1;
	
}

int main()
{
	char from[20], to[20];
	while(scanf("%s", from) != EOF) 
	{
		scanf("%s", to);
		scol = from[0] - 'a';
		srow = from[1] - '0';
		ecol = to[0] - 'a';
		erow = to[1] - '0';
		int h = heuristic(scol,srow);
		int g = 0;
		int f = g + h;
		Knight start(f, g, h);
		start.x = scol;
		start.y = srow;
		
		while(!openList.empty())
			openList.pop();
		memset(mp, 0, sizeof(int)*MAX_SIZE*MAX_SIZE);
		//2、将起始点加入开放列表
		openList.push(start);
		cout<<Astar()<<endl;
	}
	return 0;
}

oj

Knight Moves

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值