POJ3083 -- BFS和DFS

這個題目就是考了圖的BFS和DFS。

BFS用於求最短路徑,這個非常簡單。 DFS用於求左優先和右優先的路徑,難點在於它的下一步方向是由上一步的方向確定的,因此每一步我們都需要確定當前的正方向。

 

一.在這裏,我們定義了一個數據類型,用於存放迷宮中點的座標以及當前行走的步數。

typedef struct Data{
    int row;
    int col;
    int step;
}Data;


 

二.BFS中,我們定義的循環隊列數組裏存放的就是Data數據類型,每次走過了該點,需要標註一下,以後就不再走了。

 

typedef struct que{
    Data data[MAX];
    int front;
    int rear;
}que;


 

void BFS(que* q ){

    while(q->front != q->rear){
        Data d =deQ(q);
        if(d.row==end.row && d.col==end.col){  //到達終點
            short_count = d.step;
            return 0;
        }
        Data temp;
        if(d.row>0 && maze[d.row-1][d.col]==1){ //迷宮向上走一步
            temp.row = d.row-1;
            temp.col = d.col;
            temp.step = d.step+1;
            enQ(q,temp);
            maze[d.row-1][d.col]= 0;  //走過了置0
        }
        if(d.row < row-1 && maze[d.row+1][d.col]==1){ //迷宮向下走一步
            temp.row = d.row+1;
            temp.col = d.col;
            temp.step = d.step+1;
            enQ(q,temp);
            maze[d.row+1][d.col]= 0;  //走過了置0
        }
        if(d.col > 0 && maze[d.row][d.col-1]==1){ //迷宮向左走一步
            temp.row = d.row;
            temp.col = d.col-1;
            temp.step = d.step+1;
            enQ(q,temp);
            maze[d.row][d.col-1]= 0;  //走過了置0
        }
        if(d.col < col-1 && maze[d.row][d.col+1]==1){ //迷宮向右走一步
            temp.row = d.row;
            temp.col = d.col+1;
            temp.step = d.step+1;
            enQ(q,temp);
            maze[d.row][d.col+1]= 0;  //走過了置0
        }
    }
}

 

三。DFS求左優先路徑。

1. 在這裏我們通過d的值來判斷當前的正方向。
                

   

2.根據d值的不同,來選取不同的遍歷順序。(左優先的情況)

          

             

 

3.根據起點S來判斷,第一個正方向d值。

題中:Exactly one 'S' and one 'E' will be present in the maze, and they will always be located along one of the maze edges and never in a corner. The maze will be fully enclosed by walls ('#'), with the only openings being the 'S' and 'E'.

也就是說,起點S一定位於迷宮的某條邊上,且迷宮的四周都是被牆所環繞的,所以起點S在第一步時,只有一個方向可以走(與左右優先無關),因此,我們只需要根據起點S在哪一條邊,則可以判斷第一個方向值。

        //根據起點位置,判斷d值,即起點的當前正方向,第一步與左優先和右優先無關
        int d;
        Data temp;
        if(start.row == row-1){  //起點位於迷宮的最下面一行,則正方向向上,,下一步一定是往上走的。
            d=0;
            temp.row=start.row-1;
            temp.col = start.col;
            temp.step = start.step+1;
            DFS_Left(temp,d);
            DFS_Right(temp,d);
        }else if(start.col ==0 ){  //起點位於迷宮的最左邊那一列, 則正方向向右,下一步一定是向右走
            d=1;
            temp.row = start.row;
            temp.col = start.col+1;
            temp.step = start.step+1;
            DFS_Left(temp,d);
            DFS_Right(temp,d);
        }else if(start.row == 0) {   //起點位於迷宮的第一行 ,則正方向向下,下一步一定是向下走
            d=2;
            temp.row = start.row+1;
            temp.col = start.col;
            temp.step = start.step+1;
            DFS_Left(temp,d);
            DFS_Right(temp,d);
        }else if(start.col == col-1){        //起點位於迷宮的最右邊那一列,則正方向是向左,下一步一定是向左走
            d=3;
            temp.row=start.row;
            temp.col = start.col-1;
            temp.step = start.step+1;
            DFS_Left(temp,d);
            DFS_Right(temp,d);
        }


4.附上DFS的代碼,通過遞歸找到終點就返回。

在case語句中,用了If...else if...else if....語句。

因爲在這裏是一條路走到底,必然可以到達終點。

而在其他迷宮的DFS算法中,有的時候走不通了,需要嘗試另外一路徑,此時則用到了for()語句循環或者if...if...if...語句。

void DFS_Left(Data data,  int direct){
    //left_count++;
    if(data.col==end.col && data.row==end.row){//到達終點返回         
        left_count = data.step;
        return;
    }
    Data temp;
    switch(direct){
        case 0:{     //正方向:向上, 按照左上右下的優先順序行走
            if(data.col > 0 && maze[data.row][data.col-1]==1){ //迷宮向左走一步,此時正方向爲向左,即d=3
                temp.row = data.row;
                temp.col = data.col-1;
                temp.step = data.step+1;
                DFS_Left(temp,3);
            }else if(data.row>0 && maze[data.row-1][data.col]==1){ //迷宮向上走一步 ,此時正方向向上,即d=0
                temp.row = data.row-1;
                temp.col = data.col;
                temp.step = data.step+1;
                DFS_Left(temp,0);
            }else if(data.col < col-1 && maze[data.row][data.col+1]==1){ //迷宮向右走一步,此時正方向爲向右,即d=1
                temp.row = data.row;
                temp.col = data.col+1;
                temp.step = data.step+1;
                DFS_Left(temp,1);
            }else if(data.row < row-1 && maze[data.row+1][data.col]==1){ //迷宮向下走一步,其實就是往回走,此時正方向向下,、即d=2
                temp.row = data.row+1;
                temp.col = data.col;
                temp.step = data.step+1;
                DFS_Left(temp,2);
            }
            break;
        }

        case 1:{ //正方向:向右, 按照上右下左的優先順序行走
            if(data.row>0 && maze[data.row-1][data.col]==1){ //迷宮向上走一步 ,此時正方向向上,即d=0
                temp.row = data.row-1;
                temp.col = data.col;
                temp.step = data.step+1;
                DFS_Left(temp,0);
            }else if(data.col < col-1 && maze[data.row][data.col+1]==1){ //迷宮向右走一步,此時正方向爲向右,即d=1
                temp.row = data.row;
                temp.col = data.col+1;
                temp.step = data.step+1;
                DFS_Left(temp,1);
            }else if(data.row < row-1 && maze[data.row+1][data.col]==1){ //迷宮向下走一步,其實就是往回走,此時正方向向下,、即d=2
                temp.row = data.row+1;
                temp.col = data.col;
                temp.step = data.step+1;
                DFS_Left(temp,2);
            }else if(data.col > 0 && maze[data.row][data.col-1]==1){ //迷宮向左走一步,此時正方向爲向左,即d=3
                temp.row = data.row;
                temp.col = data.col-1;
                temp.step = data.step+1;
                DFS_Left(temp,3);
            }
            break;
        }

        case 2:{  //正方向:向下,按照右下左上的優先順序行走
            if(data.col < col-1 && maze[data.row][data.col+1]==1){ //迷宮向右走一步,此時正方向爲向右,即d=1
                temp.row = data.row;
                temp.col = data.col+1;
                temp.step = data.step+1;
                DFS_Left(temp,1);
            }else if(data.row < row-1 && maze[data.row+1][data.col]==1){ //迷宮向下走一步,其實就是往回走,此時正方向向下,、即d=2
                temp.row = data.row+1;
                temp.col = data.col;
                temp.step = data.step+1;
                DFS_Left(temp,2);
            }else if(data.col > 0 && maze[data.row][data.col-1]==1){ //迷宮向左走一步,此時正方向爲向左,即d=3
                temp.row = data.row;
                temp.col = data.col-1;
                temp.step = data.step+1;
                DFS_Left(temp,3);
            }else if(data.row>0 && maze[data.row-1][data.col]==1){ //迷宮向上走一步 ,此時正方向向上,即d=0
                temp.row = data.row-1;
                temp.col = data.col;
                temp.step = data.step+1;
                DFS_Left(temp,0);
            }
            break;
        }

        case 3:{ //正方向:向左,按照下左上右的優先順序行走
            if(data.row < row-1 && maze[data.row+1][data.col]==1){ //迷宮向下走一步,其實就是往回走,此時正方向向下,、即d=2
                temp.row = data.row+1;
                temp.col = data.col;
                temp.step = data.step+1;
                DFS_Left(temp,2);
            }else if(data.col > 0 && maze[data.row][data.col-1]==1){ //迷宮向左走一步,此時正方向爲向左,即d=3
                temp.row = data.row;
                temp.col = data.col-1;
                temp.step = data.step+1;
                DFS_Left(temp,3);
            }else if(data.row>0 && maze[data.row-1][data.col]==1){ //迷宮向上走一步 ,此時正方向向上,即d=0
                temp.row = data.row-1;
                temp.col = data.col;
                temp.step = data.step+1;
                DFS_Left(temp,0);
            }else if(data.col < col-1 && maze[data.row][data.col+1]==1){ //迷宮向右走一步,此時正方向爲向右,即d=1
                temp.row = data.row;
                temp.col = data.col+1;
                temp.step = data.step+1;
                DFS_Left(temp,1);
            }
            break;
        }
    }
}


5.在進行右優先遍歷的時候, 假如此時正方向向上,遍歷的優先順序是: 右 - 上 - 左 - 下, 而不是右 - 下 - 左 - 上。

 

四。附上全部源碼。

#include <stdio.h>
#include <stdlib.h>
int maze[40][40];
int left_count,right_count,short_count;

#define MAX 120

typedef struct Data{
    int row;
    int col;
    int step;
}Data;
Data start; //定義起點
Data end;   //定義終點
int row ,col;

typedef struct que{
    Data data[MAX];
    int front;
    int rear;
}que;

que* initQue(){
    que* q = (que*) malloc(sizeof(que));
    memset(q,0,sizeof(que));
    return q;
}

int enQ(que* q , Data d){
    if((q->rear+1)%MAX == q->front){  //隊滿返回0
        return 0;
    }
    q->data[q->rear].row = d.row;  //將X/Y座標輸入隊列
    q->data[q->rear].col = d.col;
    q->data[q->rear].step = d.step;
    q->rear =(q->rear+1)%MAX;
    return 1;
}

Data deQ(que*q){
    /*if(q->front == q->rear){  //隊空,返回NULL
        return NULL;
    }*/
    Data d = q->data[q->front];
    q->front = (q->front+1)%MAX;
    return d;
}

void BFS(que* q ){

    while(q->front != q->rear){
        Data d =deQ(q);
        if(d.row==end.row && d.col==end.col){  //到達終點
            short_count = d.step;
            return 0;
        }
        Data temp;
        if(d.row>0 && maze[d.row-1][d.col]==1){ //迷宮向上走一步
            temp.row = d.row-1;
            temp.col = d.col;
            temp.step = d.step+1;
            enQ(q,temp);
            maze[d.row-1][d.col]= 0;  //走過了置0
        }
        if(d.row < row-1 && maze[d.row+1][d.col]==1){ //迷宮向下走一步
            temp.row = d.row+1;
            temp.col = d.col;
            temp.step = d.step+1;
            enQ(q,temp);
            maze[d.row+1][d.col]= 0;  //走過了置0
        }
        if(d.col > 0 && maze[d.row][d.col-1]==1){ //迷宮向左走一步
            temp.row = d.row;
            temp.col = d.col-1;
            temp.step = d.step+1;
            enQ(q,temp);
            maze[d.row][d.col-1]= 0;  //走過了置0
        }
        if(d.col < col-1 && maze[d.row][d.col+1]==1){ //迷宮向右走一步
            temp.row = d.row;
            temp.col = d.col+1;
            temp.step = d.step+1;
            enQ(q,temp);
            maze[d.row][d.col+1]= 0;  //走過了置0
        }
    }
}

//1.正方向:向上d=0; 2.正方向:向右d=1 3.正方向:向下d=2  4.正方向:向左d=3
void DFS_Left(Data data,  int direct){
    //left_count++;
    if(data.col==end.col && data.row==end.row){
        left_count = data.step;
        return;
    }
    Data temp;
    switch(direct){
        case 0:{     //正方向:向上, 按照左上右下的優先順序行走
            if(data.col > 0 && maze[data.row][data.col-1]==1){ //迷宮向左走一步,此時正方向爲向左,即d=3
                temp.row = data.row;
                temp.col = data.col-1;
                temp.step = data.step+1;
                DFS_Left(temp,3);
            }else if(data.row>0 && maze[data.row-1][data.col]==1){ //迷宮向上走一步 ,此時正方向向上,即d=0
                temp.row = data.row-1;
                temp.col = data.col;
                temp.step = data.step+1;
                DFS_Left(temp,0);
            }else if(data.col < col-1 && maze[data.row][data.col+1]==1){ //迷宮向右走一步,此時正方向爲向右,即d=1
                temp.row = data.row;
                temp.col = data.col+1;
                temp.step = data.step+1;
                DFS_Left(temp,1);
            }else if(data.row < row-1 && maze[data.row+1][data.col]==1){ //迷宮向下走一步,其實就是往回走,此時正方向向下,、即d=2
                temp.row = data.row+1;
                temp.col = data.col;
                temp.step = data.step+1;
                DFS_Left(temp,2);
            }
            break;
        }

        case 1:{ //正方向:向右, 按照上右下左的優先順序行走
            if(data.row>0 && maze[data.row-1][data.col]==1){ //迷宮向上走一步 ,此時正方向向上,即d=0
                temp.row = data.row-1;
                temp.col = data.col;
                temp.step = data.step+1;
                DFS_Left(temp,0);
            }else if(data.col < col-1 && maze[data.row][data.col+1]==1){ //迷宮向右走一步,此時正方向爲向右,即d=1
                temp.row = data.row;
                temp.col = data.col+1;
                temp.step = data.step+1;
                DFS_Left(temp,1);
            }else if(data.row < row-1 && maze[data.row+1][data.col]==1){ //迷宮向下走一步,其實就是往回走,此時正方向向下,、即d=2
                temp.row = data.row+1;
                temp.col = data.col;
                temp.step = data.step+1;
                DFS_Left(temp,2);
            }else if(data.col > 0 && maze[data.row][data.col-1]==1){ //迷宮向左走一步,此時正方向爲向左,即d=3
                temp.row = data.row;
                temp.col = data.col-1;
                temp.step = data.step+1;
                DFS_Left(temp,3);
            }
            break;
        }

        case 2:{  //正方向:向下,按照右下左上的優先順序行走
            if(data.col < col-1 && maze[data.row][data.col+1]==1){ //迷宮向右走一步,此時正方向爲向右,即d=1
                temp.row = data.row;
                temp.col = data.col+1;
                temp.step = data.step+1;
                DFS_Left(temp,1);
            }else if(data.row < row-1 && maze[data.row+1][data.col]==1){ //迷宮向下走一步,其實就是往回走,此時正方向向下,、即d=2
                temp.row = data.row+1;
                temp.col = data.col;
                temp.step = data.step+1;
                DFS_Left(temp,2);
            }else if(data.col > 0 && maze[data.row][data.col-1]==1){ //迷宮向左走一步,此時正方向爲向左,即d=3
                temp.row = data.row;
                temp.col = data.col-1;
                temp.step = data.step+1;
                DFS_Left(temp,3);
            }else if(data.row>0 && maze[data.row-1][data.col]==1){ //迷宮向上走一步 ,此時正方向向上,即d=0
                temp.row = data.row-1;
                temp.col = data.col;
                temp.step = data.step+1;
                DFS_Left(temp,0);
            }
            break;
        }

        case 3:{ //正方向:向左,按照下左上右的優先順序行走
            if(data.row < row-1 && maze[data.row+1][data.col]==1){ //迷宮向下走一步,其實就是往回走,此時正方向向下,、即d=2
                temp.row = data.row+1;
                temp.col = data.col;
                temp.step = data.step+1;
                DFS_Left(temp,2);
            }else if(data.col > 0 && maze[data.row][data.col-1]==1){ //迷宮向左走一步,此時正方向爲向左,即d=3
                temp.row = data.row;
                temp.col = data.col-1;
                temp.step = data.step+1;
                DFS_Left(temp,3);
            }else if(data.row>0 && maze[data.row-1][data.col]==1){ //迷宮向上走一步 ,此時正方向向上,即d=0
                temp.row = data.row-1;
                temp.col = data.col;
                temp.step = data.step+1;
                DFS_Left(temp,0);
            }else if(data.col < col-1 && maze[data.row][data.col+1]==1){ //迷宮向右走一步,此時正方向爲向右,即d=1
                temp.row = data.row;
                temp.col = data.col+1;
                temp.step = data.step+1;
                DFS_Left(temp,1);
            }
            break;
        }
    }
}

void DFS_Right(Data data,  int direct){
        if(data.col==end.col && data.row==end.row){
        right_count = data.step;
        return;
    }
    Data temp;
    switch(direct){
        case 0:{     //正方向:向上, 按照右上左下的優先順序行走
            if(data.col < col-1 && maze[data.row][data.col+1]==1){ //迷宮向右走一步,此時正方向爲向右,即d=1
                temp.row = data.row;
                temp.col = data.col+1;
                temp.step = data.step+1;
                DFS_Right(temp,1);
            }else if(data.row>0 && maze[data.row-1][data.col]==1){ //迷宮向上走一步 ,此時正方向向上,即d=0
                temp.row = data.row-1;
                temp.col = data.col;
                temp.step = data.step+1;
                DFS_Right(temp,0);
            }else if(data.col > 0 && maze[data.row][data.col-1]==1){ //迷宮向左走一步,此時正方向爲向左,即d=3
                temp.row = data.row;
                temp.col = data.col-1;
                temp.step = data.step+1;
                DFS_Right(temp,3);
            }else if(data.row < row-1 && maze[data.row+1][data.col]==1){ //迷宮向下走一步,其實就是往回走,此時正方向向下,、即d=2
                temp.row = data.row+1;
                temp.col = data.col;
                temp.step = data.step+1;
                DFS_Right(temp,2);
            }
            break;
        }

        case 1:{ //正方向:向右, 按照下右上左的優先順序行走
            if(data.row < row-1 && maze[data.row+1][data.col]==1){ //迷宮向下走一步,其實就是往回走,此時正方向向下,、即d=2
                temp.row = data.row+1;
                temp.col = data.col;
                temp.step = data.step+1;
                DFS_Right(temp,2);
            }else if(data.col < col-1 && maze[data.row][data.col+1]==1){ //迷宮向右走一步,此時正方向爲向右,即d=1
                temp.row = data.row;
                temp.col = data.col+1;
                temp.step = data.step+1;
                DFS_Right(temp,1);
            }else if(data.row>0 && maze[data.row-1][data.col]==1){ //迷宮向上走一步 ,此時正方向向上,即d=0
                temp.row = data.row-1;
                temp.col = data.col;
                temp.step = data.step+1;
                DFS_Right(temp,0);
            }else if(data.col > 0 && maze[data.row][data.col-1]==1){ //迷宮向左走一步,此時正方向爲向左,即d=3
                temp.row = data.row;
                temp.col = data.col-1;
                temp.step = data.step+1;
                DFS_Right(temp,3);
            }
            break;
        }

        case 2:{  //正方向:向下,按照左下右上的優先順序行走
            if(data.col > 0 && maze[data.row][data.col-1]==1){ //迷宮向左走一步,此時正方向爲向左,即d=3
                temp.row = data.row;
                temp.col = data.col-1;
                temp.step = data.step+1;
                DFS_Right(temp,3);
            }else if(data.row < row-1 && maze[data.row+1][data.col]==1){ //迷宮向下走一步,其實就是往回走,此時正方向向下,、即d=2
                temp.row = data.row+1;
                temp.col = data.col;
                temp.step = data.step+1;
                DFS_Right(temp,2);
            }else if(data.col < col-1 && maze[data.row][data.col+1]==1){ //迷宮向右走一步,此時正方向爲向右,即d=1
                temp.row = data.row;
                temp.col = data.col+1;
                temp.step = data.step+1;
                DFS_Right(temp,1);
            }else if(data.row>0 && maze[data.row-1][data.col]==1){ //迷宮向上走一步 ,此時正方向向上,即d=0
                temp.row = data.row-1;
                temp.col = data.col;
                temp.step = data.step+1;
                DFS_Right(temp,0);
            }
            break;
        }

        case 3:{ //正方向:向左,按照上左下右的優先順序行走
             if(data.row>0 && maze[data.row-1][data.col]==1){ //迷宮向上走一步 ,此時正方向向上,即d=0
                temp.row = data.row-1;
                temp.col = data.col;
                temp.step = data.step+1;
                DFS_Right(temp,0);
            }else if(data.col > 0 && maze[data.row][data.col-1]==1){ //迷宮向左走一步,此時正方向爲向左,即d=3
                temp.row = data.row;
                temp.col = data.col-1;
                temp.step = data.step+1;
                DFS_Right(temp,3);
            }else if(data.row < row-1 && maze[data.row+1][data.col]==1){ //迷宮向下走一步,其實就是往回走,此時正方向向下,、即d=2
                temp.row = data.row+1;
                temp.col = data.col;
                temp.step = data.step+1;
                DFS_Right(temp,2);
            }else if(data.col < col-1 && maze[data.row][data.col+1]==1){ //迷宮向右走一步,此時正方向爲向右,即d=1
                temp.row = data.row;
                temp.col = data.col+1;
                temp.step = data.step+1;
                DFS_Right(temp,1);
            }
            break;
        }
    }
}


int main()
{
    int n;
    //freopen("input.txt","r",stdin);
    scanf("%d",&n);
    int i =0;
    for(i=0;i<n;i++){
        memset(maze,0,sizeof(maze)); //迷宮初始化爲0,不能初始化爲1,每個值會認爲是00000001 00000001 00000001
        left_count =1;
        right_count=1;
        short_count=0;
        scanf("%d%d",&col,&row);
        int j,k;
        for(j=0;j<row;j++){
            for(k=0;k<col;k++){
                char c;
                scanf("%c",&c);
                while(c=='\n' || c==' '){
                   scanf("%c",&c);
                }
                if(c=='.'){
                    maze[j][k]=1; //空地爲1
                }else if(c== 'S'){
                    maze[j][k] = 1;  //起點爲1,並記錄起點座標
                    start.row = j;
                    start.col =k;
                    start.step = 1;
                }else if(c=='E'){
                    maze[j][k]=1; //終點爲1,並記錄終點座標
                    end.row =j;
                    end.col = k;
                    end.step=0;
                }
            }
        }

        //根據起點位置,判斷d值,即起點的當前正方向,第一步與左優先和右優先無關
        int d;
        Data temp;
        if(start.row == row-1){  //起點位於迷宮的最下面一行,則正方向向上,,下一步一定是往上走的。
            d=0;
            temp.row=start.row-1;
            temp.col = start.col;
            temp.step = start.step+1;
            DFS_Left(temp,d);
            DFS_Right(temp,d);
        }else if(start.col ==0 ){  //起點位於迷宮的最左邊那一列, 則正方向向右,下一步一定是向右走
            d=1;
            temp.row = start.row;
            temp.col = start.col+1;
            temp.step = start.step+1;
            DFS_Left(temp,d);
            DFS_Right(temp,d);
        }else if(start.row == 0) {   //起點位於迷宮的第一行 ,則正方向向下,下一步一定是向下走
            d=2;
            temp.row = start.row+1;
            temp.col = start.col;
            temp.step = start.step+1;
            DFS_Left(temp,d);
            DFS_Right(temp,d);
        }else if(start.col == col-1){        //起點位於迷宮的最右邊那一列,則正方向是向左,下一步一定是向左走
            d=3;
            temp.row=start.row;
            temp.col = start.col-1;
            temp.step = start.step+1;
            DFS_Left(temp,d);
            DFS_Right(temp,d);
        }


        printf("%d %d ",left_count,right_count);
        que* q = initQue();
        enQ(q,start);
        BFS(q);
        printf("%d\n",short_count);
    }

    return 0;
}


 

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