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;
}

qsort函數講解:C語言排序qsort函數

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章