深搜&&廣搜_Poj_3083

//題目大意是一直靠着左邊牆往前走,記下找到終點的步數
//再一直靠着右邊牆往前走,記下找到終點的步數
//然後用廣搜搜出到達終點所需的最短的步數
//PS:<1>到達某一點時要記錄到達時所面對的方向 
//         <2>到達某一點後,要弄清搜索4個方向的順序搜索的方向是和所靠的牆的方向是相反的

//       比如靠着左牆走,那麼一點搜索到左邊是牆,就有往該(面對牆)方向往右前進


//PS2:絕對到苦力題啊! T.T  做的我淚流滿面

//PS3 :加強了搜索題中對頂點各個方向的處理能力


#include<iostream>
#include<queue>
using namespace std;

//定義往左深搜的搜索順序數組,0,1,2,3分別代表右上左下
int go_left_x[4]={0,-1,0,1};
int go_left_y[4]={1,0,-1,0};

//定義往右深搜的搜索順序數組,0,1,2,3分別代表右下左上
int go_right_x[4]={0,1,0,-1};
int go_right_y[4]={1,0,-1,0};

//定義到達終點所用的步數
int left_sum,right_sum,least_sum;

/*------以下爲兩種搜索共用的變量--------*/

//定義輸入圖的個數
int n;

//存儲地圖
char g[41][41];

//存儲圖的縱數和橫數
int g_y,g_x;

//定義開始點和結束點的座標
int start_x,start_y,end_x,end_y;

//看是否在圖內
bool IsIn(int now_x,int now_y)
{
if(now_x<0||now_x>=g_x||now_y<0||now_y>=g_y) return false;
else return true;
}

//左深搜,direction代表進入該點時所面對的方向,num代表走到該點所用的步數
void dfs_left(int now_x,int now_y,int direction,int num)
{
if(now_x==end_x && now_y==end_y)
left_sum=num;
else
{
//定義到當前方向的左邊並開始四個方向順序遍歷,選且只選其中一個方向
direction=(direction+1)%4;//將右上左下四個方向分別標記0,1,2,3,所以往左轉就是(當前方向+1)%4
//開始遍歷,如果當前方向不成功就往右轉,就是(當前方向+1)%4
int next_x,next_y;
int i;
for(i=0;i<4;i++)
{
next_x=now_x+go_left_x[direction];
next_y=now_y+go_left_y[direction];
//如果當前前進方向的各自在圖內且可走,則前進且終斷當前循環,因爲每一步只選一種方向
if(IsIn(next_x,next_y) && g[next_x][next_y]!='#')
{
dfs_left(next_x,next_y,direction,num+1);
break;
}
//不成功,右轉
else direction=(direction+3)%4;
}
}
}

//複製上面的稍加修改:右深搜,direction代表進入該點時所面對的方向,num代表走到該點所用的步數
void dfs_right(int now_x,int now_y,int direction,int num)
{
if(now_x==end_x && now_y==end_y)
right_sum=num;
else
{
//定義到當前方向的左邊並開始四個方向順序遍歷,選且只選其中一個方向
direction=(direction+1)%4;//將右下左上四個方向分別標記0,1,2,3,所以往左轉就是(當前方向+1)%4
//開始遍歷,如果當前方向不成功就往右轉(即保證靠着牆前進),就是(當前方向+3)%4
int next_x,next_y;
int i;
for(i=0;i<4;i++)
{
next_x=now_x+go_right_x[direction];
next_y=now_y+go_right_y[direction];
//如果當前前進方向的各自在圖內且可走,則前進且終斷當前循環,因爲每一步只選一種方向
if(IsIn(next_x,next_y) && g[next_x][next_y]!='#')
{
dfs_right(next_x,next_y,direction,num+1);
break;
}
//不成功,左轉
else direction=(direction+3)%4;
}
}
}

//接下來定義廣搜所要用到的
bool sign[40][40];

struct Node
{
int x,y,num;
}node[41][41];

//定義隊列
queue<Node>Q;

void bfs()
{
int now_x, now_y,now_num;
now_x=Q.front().x;
now_y=Q.front().y;
now_num=Q.front().num;
//遍歷四個方向可達的點併入棧
int tx,ty;
int i;
for(i=0;i<4;i++)
{
//用go_left_x和go_right_x都一樣,目的只是訪問四個方向頂點,順序如何無妨
tx=now_x+go_left_x[i];
ty=now_y+go_left_y[i];
if(IsIn(tx,ty) && !sign[tx][ty] && g[tx][ty]!='#')//在圖上且未訪問過的點同時不是牆的,入隊列
{
//標記node[tx][ty]已經訪問過
sign[tx][ty]=true;


node[tx][ty].x=tx;
node[tx][ty].y=ty;
node[tx][ty].num=now_num+1;

Q.push(node[tx][ty]);
}
}
Q.pop();
while(!Q.empty())
{
now_x=Q.front().x;
now_y=Q.front().y;
now_num=Q.front().num;
//如果已經是終點則返回,終止搜索
if(now_x==end_x && now_y==end_y)
{
least_sum=now_num;
return;
}
for(i=0;i<4;i++)
{
tx=now_x+go_left_x[i];
ty=now_y+go_left_y[i];
if(IsIn(tx,ty) && !sign[tx][ty] && g[tx][ty]!='#')//在圖上且未訪問過的點同時不是牆的,入隊列
{
sign[tx][ty]=true;


node[tx][ty].x=tx;
node[tx][ty].y=ty;
node[tx][ty].num=now_num+1;
Q.push(node[tx][ty]);
}
}
Q.pop();
}
}

int main()
{
while(cin>>n)
{
while(n--)
{
cin>>g_y>>g_x;//先輸入列才輸入行
int i,j;
for(i=0;i<g_x;i++)
scanf("%s",g[i]);
//記錄下開始頂點和結束頂點
for(i=0;i<g_x;i++)
{
for(j=0;j<g_y;j++)
{
if(g[i][j]=='S')
{
start_x = i;
start_y = j;
}
if(g[i][j]=='E')
{
end_x = i;
end_y = j;
}
}
}
//確定開始時面對的方向
int direction;
if(start_x==g_x-1) direction=1;//開始時方向朝上
else if(start_x-1 == 0) direction=3;//方向朝下
else if(start_y == 0) direction=0;//方向朝右
else direction=2;//方向朝左
//往左深搜
dfs_left(start_x,start_y,direction,1);
printf("%d ",left_sum);
//往右深搜(方向數字不同,重新確定方向數字)
if(start_x==g_x-1) direction=3;//開始時方向朝上
else if(start_x-1 == 0) direction=1;//方向朝下
else if(start_y == 0) direction=0;//方向朝右
else direction=2;//方向朝左
dfs_right(start_x,start_y,direction,1);
printf("%d ",right_sum);
//廣搜
memset(sign,0,sizeof(sign));
while(!Q.empty())
Q.pop();
node[start_x][start_y].x=start_x;
node[start_x][start_y].y=start_y;
node[start_x][start_y].num=1;
sign[start_x][start_y] = true;
Q.push(node[start_x][start_y]);
bfs();
printf("%d\n",least_sum);
}
}
return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章