1. 程式人生 > >DFS深度優先搜尋(1)--poj3984(基本模板題)

DFS深度優先搜尋(1)--poj3984(基本模板題)

                                                                                                                             迷宮問題

Description

定義一個二維陣列:
int maze[5][5] = {

	0, 1, 0, 0, 0,

	0, 1, 0, 1, 0,

	0, 0, 0, 0, 0,

	0, 1, 1, 1, 0,

	0, 0, 0, 1, 0,

};

它表示一個迷宮,其中的1表示牆壁,0表示可以走的路,只能橫著走或豎著走,不能斜著走,要求程式設計序找出從左上角到右下角的最短路線。

Input

一個5 × 5的二維陣列,表示一個迷宮。資料保證有唯一解。

Output

左上角到右下角的最短路徑,格式如樣例所示。

Sample Input

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

Sample Output

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

          注意:下面是我一開始的錯誤的想法以及程式碼難過

       這道題可以用很多方法,bfs,dfs都可以解決,dfs寫的程式碼要少一點,我就用了dfs,我開始想的是用dfs把所有能達到終點的路徑全找出來,來比較找到最短的路徑,但是由於要輸出最短的路徑,這樣感覺行不通;後來想了一下,這道題是從左上角達到右下角,為使路徑最短,肯定是儘量先往下或者往右走,這樣尋找的第一條路徑就一定是最短的,所以我把方向陣列(d陣列)的第一個和第二個方向分別設為往右和往下,這樣只要找到的第一條路徑就一定是最短的,找到後就直接終止尋找了。上程式碼:

#include<stdio.h>
struct node{
	int x,y;
}path[20];  //存最短的路徑
int maze[7][7];
int flag=0;     //標記是否找到一條路
int d[4][2]={0,1,1,0,-1,0,0,-1};//上下左右四個方向  先往右和往下使路徑最短
int vis[7][7]={0};
void Dfs(int x,int y,int step){   //step記錄當前步數
	int i;
	if(flag)return;    //一旦找到某一條路(這條路肯定是最短路)就結束尋找的過程
	if(x==4&&y==4){
		flag=step;      //標記為已找到 並記錄步數
		return;
	}
	for(i=0;i<4;i++){
		int xx=x+d[i][0];
		int yy=y+d[i][1];
		if(xx<0||yy<0||xx>4||yy>4)continue;
		if(maze[xx][yy]==1)continue;
		if(vis[xx][yy])continue;
		vis[xx][yy]=1;
		path[step+1].x=xx;
		path[step+1].y=yy;    //記錄每一步
		Dfs(xx,yy,step+1);
		if(flag)return;  //這個語句至關重要,一旦找到某一條路(這條路肯定是最短路)就結束尋找的過程
		vis[xx][yy]=0;   //否則會使記錄下的路徑(即用path陣列存的)發生改變
	}
}
int main()
{
	int i,j;
	for(i=0;i<5;i++){
		for(j=0;j<5;j++){
			scanf("%d",&maze[i][j]);
		}
	}
	path[0].x=path[0].y=0;  //從路徑(0,0)開始
	Dfs(0,0,0);
	for(i=0;i<=flag;i++){
		printf("(%d, %d)\n",path[i].x,path[i].y);
	}
	return 0;
}

           注意:為什麼說我上面的想法是錯誤的呢?

       因為有類似於這種情況的出現

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

           類似於這種情況出現的話,這種方法就不對了,然而上面的程式碼卻過了,==無語......只能說後臺資料太水了,不是同學提醒我,我還不曉得我錯了呢。。。。。。算了,我還是用Bfs(每個點要記錄上一個狀態),最後再遞迴地輸出最短路徑,正確程式碼如下:

#include<stdio.h>
#include<string.h>
#include<queue>
#include<stdlib.h>
using namespace std;
int map[7][7];
int vis[7][7];     //標記
int d[4][2]={1,0,0,1,0,-1,-1,0};      //四個方向
struct node{
	int x,y;
	int step;    //步數
	node *last;  //指向上一個狀態
};
node* Bfs(int x,int y){
	int i;
	memset(vis,0,sizeof(vis));
	vis[0][0]=1;
	queue<node *>q;
	node *s;
	s=(node *)malloc(sizeof(node));
	s->x=x;
	s->y=y;
	s->step=0;
	s->last=NULL;
	q.push(s);
	while(!q.empty()){
		s=q.front();
		q.pop();
		if(s->x==4&&s->y==4)
			return s;
		for(i=0;i<4;i++){
			int xx=s->x+d[i][0];
			int yy=s->y+d[i][1];
			if(xx<0||yy<0||xx>4||yy>4)continue;
			if(map[xx][yy])continue;
			if(vis[xx][yy])continue;
			vis[xx][yy]=1;
			node *e;       //注意e必須定義在迴圈裡面
			e=(node *)malloc(sizeof(node));
			e->x=xx;
			e->y=yy;
			e->step=s->step+1;
			e->last=s;
			q.push(e);
		}
	}
	return NULL;
}
void Output(node *s){    //遞迴地輸出路徑
	if(s==NULL)return;
	Output(s->last);
	printf("(%d, %d)\n",s->x,s->y);
}
int main()
{
	int i,j;
	for(i=0;i<5;i++){
		for(j=0;j<5;j++){
			scanf("%d",&map[i][j]);
		}
	}
	Output(Bfs(0,0));
	return 0;
}