SDU--Maze--2020-02-26

题目描述

  东东有一张地图,想通过地图找到妹纸。地图显示,0表示可以走,1表示不可以走,左上角是入口,右下角是妹纸,这两个位置保证为0。既然已经知道了地图,那么东东找到妹纸就不难了,请你编一个程序,写出东东找到妹纸的最短路线。

输入

  输入是一个5 × 5的二维数组,仅由0、1两数字组成,表示法阵地图。

输出

  输出若干行,表示从左上角到右下角的最短路径依次经过的坐标,格式如样例所示。数据保证有唯一解。

样例输入

0 1 0 0 0
0 1 0 1 0
0 1 0 1 0
0 0 0 1 0
0 1 0 1 0

样例输出

(0, 0)
(1, 0)
(2, 0)
(3, 0)
(3, 1)
(3, 2)
(2, 2)
(1, 2)
(0, 2)
(0, 3)
(0, 4)
(1, 4)
(2, 4)
(3, 4)
(4, 4)

思路

综述

  从点(0,0)开始广度优先搜索:每到达一个点,对该点打上标记。接着遍历该点的上下左右四方向的点,如果满足1)没有越界;2)没有被标记过;3)该点可以到达,即不是墙;则记录一下该点,同时记录该点的父节点(也就是上一个点),并且入队。遍历完四个方向之后,接下来从队列中取出一个点,进行上述操作,直到遇到点(4,4);然后借助每个点都记录过父节点,回溯到(0,0)依次入栈,再依次出栈得到正确的路线。

主要变量解释

结构体point:
number(int):用于标记点在Point中的位置
x(int):用于记录点的横坐标
y(int):用于记录点的纵坐标
last(int):用于记录点的父节点
vis(int):二维数组,用于标记点是否到达过
dis(int):二维数组,用于记录每个点距离(0,0)的距离
road(int):二维数组,用于标记是墙还是通路
qq(<queue>):用于广度优先搜索记录遍历过的点
way(<stack>):用于回溯到起点的栈
next(int):全局变量,用于目前标记所到达的点,是全局的第几个点
dx,dy(int):一维数组,为某点遍历四个方向提供便利

过程

step1:记录P(0).x=P(0).y=P(0).number=P(0).last=0;打标记:vis(0,0)=1;该点入队qq
step2:从队列qq中pop出一个元素 now进入step3
step3:依次遍历该点的上、下、左、右四个方向,每遍历到一个点nextp进入step4,若遍历结束进入step2;
step4:判断该点nextp是否满足1)没有越界;2)没有被标记过;3)该点可到达,即不是墙若不满足进入step3;若满足则进入step5
step5:记录该点为P[next](next详见主要变量解释);记录P[next].last=now.number;对该点打上标记vis[P[next].x,P[next].y]=1;进入step6
step6:判断该点如果该点是(4,4);则进入step7;否则进入step3;
step7:利用栈way来从(4,4)回溯到起点(0,0)依次入栈
step8:栈中元素依次pop 得到正确的结果

代码

#include <iostream>
#include <stack>
#include <queue>
#include <string.h>
using namespace std;
struct point{
    int number; //用于标记点在Point中的位置
    int x,y;//顶点的x,y坐标
    int last;//用于记录前一个节点 
}P[5000]; 
//用于遍历某节点周围节点的变量数组 
const int dx[]={0,0,1,-1};
const int dy[]={1,-1,0,0};
 
void bfs(){
 
    int vis[5][5],dis[5][5];//分别记录某点是否经过和到某点的最短距离 
    int road[5][5];// 数组5*5  用于记录地图数据
    int i,j,k;
    //构建地图 
    for(i=0;i<5;i++)
        for(j=0;j<5;j++)
            cin>>road[i][j];
     
    //初始化 
    memset(vis,0,sizeof(int)*25);
    memset(dis,0,sizeof(int)*25);
 
    stack<point> way;//记录正确的路径
    queue<point> qq;//用于广搜
    int flag = 0 ;//用于标记是否找到出口
    int goal;
     
    //(0,0)-->(4,4)
 
    int next=0;
    P[0].x=0;
    P[0].y=0;
    P[0].last=0;
    P[0].number=0;
    qq.push(P[0]);
    vis[P[0].x][P[0].y]=1;
    dis[P[0].x][P[0].y]=0;
    while(!flag){
        point now;
        now = qq.front();
        qq.pop();
        //遍历四个方向 
             
            int pnode = now.number;  //记录父节点
             
            for(i=0;i<4;i++){
            point nextp;
            nextp.x = now.x + dx[i];
            nextp.y = now.y + dy[i];
             
            if(nextp.x>=0 && nextp.x<=4 && nextp.y>=0 && nextp.y<=4 && !vis[nextp.x][nextp.y] && !road[nextp.x][nextp.y]){
                 
                vis[nextp.x][nextp.y]=1;
                dis[nextp.x][nextp.y]=dis[now.x][now.y]+1;//记录长度 
                  
                next++;
                nextp.number=next;
                qq.push(nextp);
                P[next].x=nextp.x;
                P[next].y=nextp.y;
                P[next].number = next;
                P[next].last = pnode;
 
                if(nextp.x==4 && nextp.y==4){//找到出口
                goal = next;
                flag=1;
                break;
                }
                   
            } 
        }
    }
     //回溯到起点
    while(goal!=0){
        way.push(P[goal]);
        goal = P[goal].last;
    } 
    //输出路线
    cout<<"(0, 0)"<<endl;
    while(!way.empty()){
        cout<<"("<<way.top().x<<", "<<way.top().y<<")"<<endl;
        way.pop();
    } 
}
int main(){
    bfs();      
}

拓展

先输入地图大小N*M
路径:
(0,0)—>(N-1,M-1)

#include <iostream>
#include <stack>
#include <queue>
#include <string.h>
using namespace std;
struct point{
	int number; 
	int x,y;//顶点的x,y坐标
	int last;//用于记录前一个节点 
}P[5000]; 
//用于遍历某节点周围节点的变量数组 
const int dx[]={0,0,1,-1};
const int dy[]={1,-1,0,0};

void bfs(int N,int M){
	cout<<N<<" "<<M<<endl;
	int **vis=new int*[N];
	int **dis=new int*[N];//分别记录某点是否经过和到某点的最短距离 
	int **road=new int*[N];// 数组5*5  用于记录地图数据
	int i,j,k;
	for(i=0;i<N;i++){
		vis[i] = new int [M];
		dis[i] = new int [M];
		road[i] = new int [M];
	}
	
	//构建地图 
	for(i=0;i<N;i++)
		for(j=0;j<M;j++){
			cin>>road[i][j];
			//初始化
			vis[i][j]=0;
			dis[i][j]=0;
		} 
			
	
	//初始化 
//	memset(vis,0,sizeof(int)*(N)*(M));
//	memset(dis,0,sizeof(int)*(N)*(M));
	
	stack<point> way;//记录正确的路径
	queue<point> qq;//用于广搜
	int flag = 0 ;//用于标记是否找到出口
	int goal;
	
	//(0,0)-->(N,M)
	int next=0;
	P[0].x=0;
	P[0].y=0;
	P[0].last=0;
	P[0].number=0;
	qq.push(P[0]);

	vis[P[0].x][P[0].y]=1;

	dis[P[0].x][P[0].y]=0;

	while(!flag){
		point now;
		now = qq.front();
		qq.pop();
		//遍历四个方向 

			int pnode = now.number;	//记录父节点

			for(i=0;i<4;i++){
			point nextp;
			nextp.x = now.x + dx[i];
			nextp.y = now.y + dy[i];


			if(nextp.x>=0 && nextp.x<=N-1 && nextp.y>=0 && nextp.y<=M-1 && !vis[nextp.x][nextp.y] && !road[nextp.x][nextp.y]){
				
				vis[nextp.x][nextp.y]=1;
				dis[nextp.x][nextp.y]=dis[now.x][now.y]+1;//记录长度 
				 
				next++;
				nextp.number=next;
				qq.push(nextp);
				P[next].x=nextp.x;
				P[next].y=nextp.y;
				P[next].number = next;
				P[next].last = pnode;


				if(nextp.x==N-1 && nextp.y==M-1){//找到出口
				goal = next;
				flag=1;
				break;
				}
				  
			} 
		}
	}
	while(goal!=0){
		way.push(P[goal]);
		goal = P[goal].last;
	} 
	cout<<"(0, 0)"<<endl;
	while(!way.empty()){
		cout<<"("<<way.top().x<<", "<<way.top().y<<")"<<endl;
		way.pop();
	} 
	for(i=0;i<N;i++){
		delete []vis[i];
		delete []dis[i];
		delete []road[i];
	}
	delete []vis;
	delete []dis;
	delete []road;
}
int main(){
	int N,M;
	cin>>N>>M;
	bfs(N,M);		
}

/*
样例输入
5 5
0 1 0 0 0
0 1 0 1 0
0 1 0 1 0
0 0 0 1 0
0 1 0 1 0
*/

问题

在拓展里面,对动态申请的二维数组vis;不能通过如下语句初始化,

memset(vis,0,sizeof(int)*N*M);
原因:

**是指向指针的指针,memset函数调用vis的话清空的是第一次申请的指针数组,对于每一个*vis[i],再调用的话就是清空数据存储去了

正确做法

如果要对二维数组进行初始化,可如下:

for(i=0;i<N;i++){
	memset(vis[i],0,sizeof(int)*(M));
	memset(dis[i],0,sizeof(int)*(M));
}
发布了29 篇原创文章 · 获赞 14 · 访问量 1271

猜你喜欢

转载自blog.csdn.net/weixin_44552961/article/details/104598607