Dijkstra算法(迪杰斯特拉算法)的地图演示

 Dijkstra算法常见用于地图寻路,但是具体怎样使用,还是有可讨论的内容的。

一、建立地图(二维数组)并在地图上设置可通行与不可通行(白色表示)的点。然后选择一个位置放置英雄(英字),选择一个位置作为目标(空方框)。

二、从地图生成逻辑的图。

1、所有的位置统一编号,采用的方法是:行坐标*宽度+列坐标。

2、每个位置只与周围八个点相连,即彼此之间有一条边。其中与上下左右的四个点之间的边的权(距离)是1,与斜方向的四个点的边的权(距离)是1.4。

3、简单处理起见,暂时用邻接矩阵法保存图

三、搜寻最短路。

用Dijkstra算法,得到从英雄位置到地图所有点的最短路,并得到路线。

四、展现路线。

使用点显示,在屏幕上展示出可视化的路径。

五、改善方向。

很明显,这种从二维地图转化来的图,节点太多,而节点之间的彼此关联很少,使用邻接矩阵法实在是浪费空间太多。如果改用前向星法,会好很多。

【完整代码展示】

#include<iostream>
#include"windows.h"
#include<sstream>         // 字符串流 
using namespace std;
int field[20][30]={};
int w=30, h=20;
int hx, hy, tx, ty;
// 邻接数组
int e[601][601];
// n个顶点,m条边,s为起点
int n, m, s; 
// 无穷大 
int inf= 99999; 
struct Point{
	// 已经确定标记 
	int mark;  
	// 当前的最短路距离
	int dis;
	// 最短路线
	string path; 
}; 
// 节点信息 
Point p[1000]; 

void gotoxy(unsigned char x,unsigned char y){
    COORD cor;
    HANDLE hout;
    cor.X = x;
    cor.Y = y;
    hout = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hout, cor);
}

string int2str(int aInt){
	stringstream res;
	res << aInt;
	string ret;
	res >> ret;
	return ret;
}
int str2int(string aStr){
	stringstream res;     // cin+cout
	res << aStr;
	int ret;
	res >> ret;
	return ret;
}

void show(){
	for (int i=0; i<h; i++){
		for (int j=0; j<w; j++){
			if (field[i][j]==0){
				if (i==hy && j==hx) {
					cout << "英";
				} else if (i==ty && j==tx){
					cout << "□";
				} else{
					cout << "  ";
				} 
			} else {
				cout << "■"; 
			}
		}
		cout << endl;
	}
}

void addEdge(int a1, int a2, int a3){
	if (a1==303 || a2==303) {
//		cout << a1 << " " << a2 << " " << a3 << endl;
	}
	e[a1][a2]= a3; 
}

void makeEdge(int i, int j){
	if (field[i][j]==1){
		return;
	}
	int id= i*w+j;
//	cout << id << endl;
	if (i>0 && field[i-1][j]==0){
		int id2= (i-1)*w+ j;
		//cout << id << " " << id2 << " " << 1 << endl;
		addEdge(id, id2, 10);
	}
	if (j>0 && field[i][j-1]==0){
		int id2= (i)*w+ j-1;
		addEdge(id, id2, 10);
	}
	if (i<h-1 && field[i+1][j]==0){
		int id2= (i+1)*w+ j;
		addEdge(id, id2, 10);
	}
	if (j<w-1 && field[i][j+1]==0){
		int id2= (i)*w+ j+1;
		addEdge(id, id2, 10);
	}
	if (i>0 && j>0 && field[i-1][j-1]==0){
		int id2= (i-1)*w+ j-1;
		addEdge(id, id2, 14);
	}
	if (i>0 && j<w-1 && field[i-1][j+1]==0){
		int id2= (i-1)*w+ j+1;
		addEdge(id, id2, 14);
	}
	if (i<h-1 && j>0 && field[i+1][j-1]==0){
		int id2= (i+1)*w+ j-1;
		addEdge(id, id2, 14);
	}
	if (i<h-1 && j<w-1 && field[i+1][j+1]==0){
		int id2= (i+1)*w+ j+1;
		addEdge(id, id2, 14);
	}
} 
void showGraph(){
	for (int i=80; i<100; i++){
		for (int j=80; j<100; j++){
			if (e[i][j]==inf){
				cout << -1 << " ";
			} else {
				cout << e[i][j] << " ";
			}
		}
		cout << endl;
	}
}

void findShortest(int s){
	// 执行Dijkstra算法
	// 首先,起点确定最短路 
	p[s].mark=1;
	p[s].path=int2str(s);
	// 第一轮标记
	for (int i=0; i<=n-1; i++){
		p[i].dis= e[s][i];
		p[i].path= int2str(s)+ "-"+ int2str(i);
	}
//	for (int i=0; i<n; i++){
//		cout << p[i].dis << " "<< p[i].path << endl;
//	}
//	return;
	// 循环n-1次,每次增加一个新的最短点 
	for (int i=1; i<=n-1; i++){
		// 找最短的距离,标记为已经确定的最短点 
		int min= inf, u=0;
		for (int j=0; j<n; j++){
			if (p[j].mark==0 && p[j].dis<min){
				min= p[j].dis;
				u=j;
			}
		} 
		p[u].mark=1;
		// 更新距离(新的最短点加入后,看看有没有变化) 
		for (int j=0; j<n; j++){
			if (p[j].dis> p[u].dis+e[u][j]){
				p[j].dis= p[u].dis+e[u][j];
				p[j].path= p[u].path+ "-"+ int2str(j);
			}
		} 
	}
}
void showPath(string s1){
	int a= s1.find('-');
	int num=0;
	while (a>=0){
		string s2= s1.substr(0,a);
		s1= s1.substr(a+1);
		a= s1.find('-');
		int b= str2int(s2);
		int x= b%w;
		int y= b/w;
//		cout << s2 << " " << y << " "<< x<< endl;
		gotoxy(x*2, y);
		if (num>0){
			cout << "·";
		}
		num++;
	}
}
int main(){
	// 初始化空场地 
	for (int i=0; i<h; i++){
		for (int j=0; j<w; j++){
			if (i==0 || j==0 || i==h-1 || j==w-1){
				field[i][j]=1;
			}
		}
	} 
	// 加障碍1
	for (int i=1; i<17; i++){
		field[i][8]=1;
	} 
	// 加障碍2
	for (int i=1; i<17; i++){
		field[h-i][20]=1;
	} 
	hx= 3;
	hy= 10;
	tx= 26;
	ty= 13;
	show();
	// 图的初始化
	n= w*h;
	for (int i=0; i<n; i++) {
		for (int j=0; j<n; j++){
			if (i==j) {
				e[i][j]=0;
			} else {
				e[i][j]=inf;
			}
		}
	}
	// 从场地生成图 
	for (int i=0; i<h; i++){
		for (int j=0; j<w; j++){
			// 编号思路 
			int id= i*w+j;
			makeEdge(i, j); 
			//cout << id << endl;
		}
	} 
	//showGraph();
	findShortest(hy*w+hx);
//	for (int i=0; i<n; i++){
//		cout << p[i].dis << " "<< p[i].path << endl;
//	}
	showPath(p[ty*w+tx].path);
//	cout << p[ty*w+tx].dis << " "<< p[ty*w+tx].path;
	while(1);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

圣手书生肖让

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值