HDU-2612-Find a way(BFS)题解-C语言

Find a way

*Time Limit: 3000/1000 MS (Java/Others)    
Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 35236    
Accepted Submission(s): 11231*

Problem Description

Pass a year learning in Hangzhou, yifenfei arrival hometown Ningbo at finally. Leave Ningbo one year, yifenfei have many people to meet. Especially a good friend Merceki.
Yifenfei’s home is at the countryside, but Merceki’s home is in the center of city. So yifenfei made arrangements with Merceki to meet at a KFC. There are many KFC in Ningbo, they want to choose one that let the total time to it be most smallest.
Now give you a Ningbo map, Both yifenfei and Merceki can move up, down ,left, right to the adjacent road by cost 11 minutes.

Input

The input contains multiple test cases.
Each test case include, first two integers n, m. (2<=n,m<=200).
Next n lines, each line included m character.
‘Y’ express yifenfei initial position.
‘M’ express Merceki initial position.
‘#’ forbid road;
‘.’ Road.
‘@’ KCF

Output

For each test case output the minimum total time that both yifenfei and Merceki to arrival one of KFC.You may sure there is always have a KFC that can let them meet.

Sample Input
4 4
Y.#@
....
.#..
@..M
4 4
Y.#@
....
.#..
@#.M
5 5
Y..@.
.#...
.#...
@..M.
#...#
Sample Output
66
88
66

题解

前言:

我看了好多题解,bfs的队列实现都是stl库的东西,但我又确实没看它,所以我就自己写了一篇题解,让我自己能看懂的。

分析题意:

输入一块地图,Y和M要到一家KFC集合,要求Y到这家KFC的时间与M到这家KFC的时间之和是所有的KFC中最短的。
最初的思路就是bfs,但是我的思路过于繁琐:先存图,在存图的过程中,将所有的KFC都存在一个新开的数组中,然后遍历每一个KFC,对每一个KFC,都进行从Y到KFC和从M到KFC的bfs,然后将他的和保存起来,最后给所有保存起来的值排序,在输出最小的值。

但是提交之后就是TEL。因为复杂度太高了,对每一个KFC,都要进行两次bfs(从Y开始和从M开始)。其中肯定有重复的步骤。
所以,经过分析:

我们可以从Y开始,对整张图进行bfs,将从Y到每个点的步数,都进行保存stepy。

同理,从M开始对整张图进行bfs,将从M到每个点的步数,进行保存stepm,保存的同时,将两个步数(从Y和从M出发)相加保存step,注意,只有两个都不为0的时候,才能保存,否则step=0。因为要保证两人都要能到。

然后遍历整张图,找出所有@里面的step,找出最小的非0 值即可。

好了,详细的都在代码里面说明:
虽然代码很长,其中有些不必要的过程,仔细看嗷

#include<stdio.h>
#include<string.h>
typedef struct NODE{//定义结构体类型
	int x;//坐标(z,y)
	int y;
	int stepy;// 从y开始的步数stepy
	int stepm;// 从m开始的步数stepm
	int step;// 总步数step
	char c;// 还有当前点的类型(@.或者#)
}node;
node map[300][300],que[90000];//地图 和 队列(用于BFS) 
int book[300][300];//标记数组 
int next[4][2]={{0,1},{0,-1},{1,0},{-1,0}};//四个方向 
int n,m; //地图大小 
int cmp(const void *a,const void *b){//这是排序函数qsort(c语言) 不懂的可以看我另一篇笔记,在文章后附有链接
	return *(int *)a-*(int *)b;
}
//从y开始的bfs函数,因为要从y和m开始的要保存在stepy和stepm不同,因此我开了两个函数,你也可以开一个嗷 
int BFSY(int sx,int sy){//sx,和sy,就是起始点的坐标,这里就是Y的坐标 
	int tail=1,head=1;//队列 
	int i,j,tx,ty;//i,j,下一点的坐标tx,ty 
	que[tail].x=sx;//队首入队 
	que[tail].y=sy; 
	que[tail].stepy=0;
	map[sx][sy].stepy=0; 
	tail++;//入队后队尾++ 
	book[sx][sy]=1;//入队标记 
	while(head<tail){//如果队空,则证明整张图已经搜完,则跳出 
		//遍历四个方向
		for(i=0;i<4;i++){
			//计算下一个点坐标
			tx=que[head].x+next[i][0]; 
			ty=que[head].y+next[i][1];
			if(tx<0||ty<0||tx>=n||ty>=m){//判断是否超出地图 
				continue;
			}
			if(book[tx][ty]==0&&(map[tx][ty].c=='.'||map[tx][ty].c=='@')){//判断是否已经走过,是否能走(#不能走) 
				book[tx][ty]=1;//标记已经走过 
				que[tail].x=tx;//入队 
				que[tail].y=ty;//入队 
				que[tail].stepy=que[head].stepy+1;//队尾的步数,就是队首的步数往前走一步,这个地方如果bfs初学,自己模拟一下出队和入队就明白了 
				map[tx][ty].stepy=que[head].stepy+1;//步数存入map对应的stepy中; 
				tail++;//队尾++ 
			}
		}
		head++;//一个点走完一四个方向,就把它出队 
	}
	return;
}
int BFSM(int sx,int sy){//bfs函数和上面一样,就是将这次的步数存到了stepm里面,并且把stepm和stepy都非零时,都加进step 
	int tail=1,head=1;
	int i,j,tx,ty;
	que[tail].x=sx;
	que[tail].y=sy;
	que[tail].stepm=0;
	map[sx][sy].stepm=0;
	if(map[sx][sy].stepm&&map[sx][sy].stepy){
		map[sx][sy].step=map[sx][sy].stepm+map[sx][sy].stepy;
	}
	tail++;
	book[sx][sy]=1;
	while(head<tail){
		for(i=0;i<4;i++){
			tx=que[head].x+next[i][0];
			ty=que[head].y+next[i][1];
			if(tx<0||ty<0||tx>=n||ty>=m){
				continue;
			}
			if(book[tx][ty]==0&&(map[tx][ty].c=='.'||map[tx][ty].c=='@')){
				book[tx][ty]=1;
				que[tail].x=tx;
				que[tail].y=ty;
				que[tail].stepm=que[head].stepm+1;
				map[tx][ty].stepm=que[head].stepm+1;
				if(map[tx][ty].stepm&&map[tx][ty].stepy){
					map[tx][ty].step=map[tx][ty].stepm+map[tx][ty].stepy;
				}
				tail++;
			}
		}
		head++;
	}
	return;
}
int main()
{
	int i,j,k,yx,yy,mx,my,a[90000];//a用来保存@上的步数 
	while(scanf("%d %d",&n,&m)!=EOF){//输入 
		memset(map,0,sizeof(map));//因为是多组输入,所以需要清空map 
		getchar();//吸收回车 
		k=0;//k用来指数组a 
		//输入地图 
		for(i=0;i<n;i++){
			for(j=0;j<m;j++){
				scanf("%c",&map[i][j].c); 
				map[i][j].x=i;
				map[i][j].y=j;
				if(map[i][j].c=='Y'){//标记y的坐标 
					yx=i;
					yy=j;
				}
				if(map[i][j].c=='M'){//标记m的坐标 
					mx=i;
					my=j;
				}
			}
			getchar();//吸收回车 
		}
		memset(book,0,sizeof(book));//清空标记数组和队列 
		memset(que,0,sizeof(que));
		BFSY(yx,yy);//从y开始的bfs 
		memset(book,0,sizeof(book));
		memset(que,0,sizeof(que));
		BFSM(mx,my);//从m开始的bfs 
		memset(a,0,sizeof(a));//清空@steo数组 
		k=0;
		//下方这个存@步数的方法有些多余,我们完全可以遍历地图,直接找出@中的非0最小值,那样更方便,自己实现吧 
		for(i=0;i<n;i++){
			for(j=0;j<m;j++){
				if(map[i][j].c=='@'&&map[i][j].step){//遇到@,则把它的步数存进a 
					a[k]=map[i][j].step;
					k++;
				}
			}
		}
		qsort(a,k,sizeof(a[0]),cmp);//对a排序 
		i=0;
		while(1){
			if(a[i]){//输出第一个非0的数 
				printf("%d\n",a[i]*11);
				break;
			}
			i++;
		}
	}
	return 0;
}

C语言排序qsort函数:

扫描二维码关注公众号,回复: 10047673 查看本文章
发布了10 篇原创文章 · 获赞 1 · 访问量 197

猜你喜欢

转载自blog.csdn.net/Huberyxiao/article/details/104341777