【蓝桥杯2019初赛】迷宫

这道题其实想法上没有什么思维局限,但是在dfs上有一个时限问题,所以需要在dfs函数中进行一定的剪枝,并且在输入上要进行循环字符输入,当然,按字典序的话,直接在刚开始就按字典序来遍历
在这里插入图片描述

//dfs代码如下

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

char map[50][100];
int book[50][100];
int mins[50][100];//此时的mins数组是记录在这一点时的最小步数是多少 
char road[1000];
char road1[1000];
int dx[4]={1,0,0,-1};
int dy[4]={0,-1,1,0};
char dir[4]={'D','L','R','U'};
int min=1000;

void dfs(int x,int y,int step)
{
	int i,j,kx,ky;
	if(x==29&&y==49){
		if(step<min){
			min=step;
			for(i=0;i<min;i++){
				road1[i]=road[i];
				//printf("%c     ",road1[i]);
			}
		}
		return;
	}
	for(i=0;i<4;i++){
		kx=x+dx[i];
		ky=y+dy[i];
		if(kx>=0&&kx<=29&&ky>=0&&ky<=49&&map[kx][ky]==0&&book[kx][ky]==0&&step+1<mins[kx][ky]){//step+1<mins 是判断如果此时到达这一步时没有原先走过这一步时步数少,这一步就不走了,类似一种剪枝 
			book[kx][ky]=1;
			mins[kx][ky]=step+1;
			road[step]=dir[i];
			dfs(kx,ky,step+1);
			book[kx][ky]=0;
		}
	}
	return;
}

int main(){
	int n,i,j;
	char a;
	for(i=0;i<30;i++){
		for(j=0;j<50;j++){
			scanf("%c",&a);
			map[i][j]=a-'0';
			mins[i][j]=10000;//使每一点的初始步数都为一个极大值,这样方便以后对这个点更新 
			book[i][j]=0; 
		}
		getchar();
	}
	book[0][0]=1;
	dfs(0,0,0);
	//printf("%d\n",min);
	for(i=0;i<min;i++){
		printf("%c",road1[i]);
	}
	printf("\n");
	return 0;
} 

可以看到除了一些dfs常规的代码,还包括一个对到达每个点时的步数进行一个统计和更新,用到了数组mins,并在刚开始时对mins进行极大值初始化,当然也可以用memset(mins,1,sizeof)这种形式进行初始化,但要记得头文件
初始化过后就是对mins的一个运用,放在dfs里进行一个判断和剪枝,当到达这一点的步数比原先这一点已有的步数小时,举个例子:

如果原先在(2,3)这个点的mins=6,此时又进行了一遍路径探索,探索到 了(2,3)这一点,但是此时的step为5,说明新的这一路径的步数到达这一点时更小,满足题目的要求,就继续这一路径的探索,并更新mins为5,反之,如果step>6,则经过(2,3)这一路径的探索就可以不用再继续了,因为再往后就是赘余,在此点已经>6了,那继续到下一个点则步数会更大,mins依然为6,无需更新
上述就是防止一个点被多次无用访问

其实这个代码在刚开始时卡在了输入map的问题上,我运用%s进行30行字符串的输入,但是整个代码一进dfs就无限循环再也出不来,所以在参考了下面博客后写出的代码,但是这位大佬好像并没有解释的很清,还有错别字(小声bb),所以我就来解释一下这个mins数组,害

https://blog.csdn.net/weixin_45483201/article/details/104148397

个人认为bfs可能是这道题更好的选择,因为bfs在遇到最小时就可快速弹出,并将路径打印出来,比dfs要快那么一些些,代码复杂度也小一些
//bfs代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>

typedef struct point{
	int x;
	int y;
	int step;//储存此时的步数 
	int father;	//储存路径 
	char dir1;//储存此时此刻方向 
}point;

char map[50][100];
int book[50][100];
char road[1000];
int dx[4]={1,0,0,-1};
int dy[4]={0,-1,1,0};
char dir[4]={'D','L','R','U'};
//int min=1000;
int tx,ty;

int main(){
	int n,i,j,k;
	char a;
	int flag=0;
	int head=0;
	int tail=0;
	point queue[10000];
	for(i=0;i<30;i++){
		for(j=0;j<50;j++){
			scanf("%c",&a);
			map[i][j]=a-'0'; 
			book[i][j]=0; 
		}
		getchar();
	}
	queue[head].x=0;
	queue[head].y=0;
	queue[head].step=0;
	queue[head].father=-1;
	book[0][0]=1;
	tail++;
	while(head!=tail){
		for(i=0;i<4;i++){
			tx=queue[head].x+dx[i];
			ty=queue[head].y+dy[i];
			if(tx>=0&&tx<=29&&ty>=0&&ty<=49&&map[tx][ty]==0&&book[tx][ty]==0){
				queue[tail].x=tx;queue[tail].y=ty;
				queue[tail].step=queue[head].step+1;
				queue[tail].father=head;
				queue[tail].dir1=dir[i];
				tail++;
				book[tx][ty]=1;
			}
			if(tx==29&&ty==49){
				flag=1;
				break;
			}
		}
		if(flag==1) break;
		head++;
	}
	k=tail-1;
	i=queue[k].step;
	j=queue[k].step;
    while(k!=-1){//将倒序路径放入数组 
	    road[i]=queue[k].dir1;
	    i--;//i最小减到1,减不到0,因为k=-1时就break 
	    k=queue[k].father;	
    }
    for(i=1;i<=j;i++){
    	printf("%c",road[i]);
    }
	printf("\n");
	return 0;
} 

相比较而言bfs在寻找的时候比较好想,也比较好实现,但是输出路径的时候真的很麻烦,要有father,针对此题还要有每一步的direction,反正这道题总体来说想法简单,实现起来有些麻烦,容易绕晕。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值