1. 程式人生 > >DFS和BFS的一點簡單總結

DFS和BFS的一點簡單總結

       DFSBFS的一點簡單總結

搜尋,簡單狹窄地講,就分為DFSBFS,但是也有一些拓展的比如迭代深搜和IDA*搜尋等等,搜尋可以說是最基礎卻又是應用最廣泛的演算法。本文簡單地總結下基礎搜尋在給定的顯式圖中的應用。

搜尋與DP,貪心,分治的共同點在於狀態的轉移,只不過在搜尋中,一個階段的最優狀態是由之前所有狀態得到的,這是其餘其他演算法的區別之處。

狀態的轉移即由某一個不同的狀態轉移至另一個不同的狀態,DFS在於從一個初始狀態出發,一直轉移狀態直到搜到目標或搜到狀態無法進行轉移為止,其中的剪枝便是通過應題目具體要求和仔細分析而去掉某些沒必要或不存在的狀態以節約時間和空間,而

BFS在於一層一層地擴充套件狀態,這樣首先找到的目標便一定是用時或步數最少的。DFS幾乎適用於所有情況,因為這本身是一種遍歷所有狀態的搜尋,只不過在尋找最小步或最小時間的情況下比較慢,無法快速找到目標,但在程式世界裡DFS本身也有不適用的情況,如果狀態沒有下限即轉移的深度沒有下限那麼便無法深搜,同樣,BFS也可能存在一層狀態都擴充套件不完的情況,這樣便才會有迭代加深搜尋等擴充套件搜尋的出現,它結合了兩者的優點且實際應用效果不錯。紫書上面的名詞解答樹便很好地描述了所有狀態轉移的過程,當然這個似乎與我們無關,但是其實也是一種刻畫搜尋過程的有利工具。

下面便是我對搜尋的心得與總結:

在具體的應用過程中:

BFSDFS通常是各有優點且相互結合,ACM屆總存在各種各樣不同的題,你無法直觀判斷你的程式碼是否正確,因為搜尋題大多不能自己去想例子來測試,只能通過題目所給的樣例來初步加以評判,不管是你是否得到正確答案,也可能出現各種卡時間、卡空間的題,因為搜尋本身的狀態數量非常大,在解答題目時你需要明白一下幾點:

1、如何進行狀態的轉移,簡單地說怎麼進行下一步的選擇,這個通常很簡單。

 2、是否需要標記已經轉移過的狀態以及怎麼標記已經轉移過的狀態以不重複轉移,你不能單一地判斷,也就是要綜合所給的題中所有出現的變化,在這個階段中,我標記這個階段時的狀態,因為很可能不止在變化,圖中的情況也在變化。

 3

、怎麼去除沒必要的或不存在的狀態,因為有些狀態是不需要進行轉移或擴充套件的。

弄清楚了以上三個問題,你就可以按題目要求從起始狀態開始搜尋了。

在解題的過程中,我也遇到了很多錯誤,當然可能更多錯誤我沒遇到或即將遇到。

從兩個簡單的搜尋題開始:

1  poj3009  Curling 2.0

題目大意要求把一個冰壺從起點“2”用最少的步數移動到終點“3”,其中0為移動區域,1為石頭區域,冰壺一旦想著某個方向運動就不會停止,也不會改變方向(想想冰壺在冰上滑動),除非冰壺撞到石頭1或者到達終點3,冰壺撞到石頭後,冰壺會停在石頭前面,此時(靜止狀態)才允許改變冰壺的運動方向,而該塊石頭會破裂,石頭所在的區域由1變為0. 也就是說,冰壺撞到石頭後,並不會取代石頭的位置。終點是一個摩擦力很大的區域,冰壺若到達終點3,就會停止在終點的位置不再移動。

首先讀懂題意:沿著某一行出發會遇到石頭才會停止,不停止則失敗,停止時石頭也會消失,還有就是我的步數不能超過10步,這就明顯告訴我們當我轉移的次數大於10時直接去掉,而且在我從某一次狀態轉移回溯後所有的情況應該沒變,所以之前在上一次轉移給石頭的標記應該去掉,然後再重新進行下一次同一深度的轉移,這個題中狀態去重很簡單,只是走過的點標記就行了。所以綜合以上分析,我只要不斷深搜取得最小步數就行了,但是之前的細節考慮是必須的。(這個問題討論BFS不可行是沒意義的,兩者都可以,雖說是尋找最小步數但是這個題目從搜尋的過程來看DFS更適合)

程式碼:

#include <cstdio>

int square[30][30];
int w, h, sx, sy;
int minnum;
int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};

void DFS(int x, int y, int cnt)
{
    if (cnt >= 10) return ;
    int i, nx, ny;
    for (i = 0; i < 4; i++){
        int flag = 1, tag = 0;
        int nx = x+dir[i][0];
        int ny = y+dir[i][1];
        while (1){
            if (nx < 1 || nx > h || ny < 1 || ny > w){
                flag = 0;
                break;
            }
            if (square[nx][ny] == 1){
                tag = 1;
                break;
            }
            if (square[nx][ny]==3 && minnum > ++cnt){
                    minnum = cnt;
                    return ;
            }
            nx += dir[i][0];
            ny += dir[i][1];
        }
        if (!flag) continue;
        if (tag){
            square[nx][ny] = 0;
            nx -= dir[i][0];
            ny -= dir[i][1];
            if (nx == x && ny == y){
                square[nx+dir[i][0]][ny+dir[i][1]] = 1;
                continue;
            }
            DFS(nx, ny, cnt+1);
            square[nx+dir[i][0]][ny+dir[i][1]] = 1;
        }
    }
}

int main()
{
    int i, j;
    while (scanf("%d %d", &w, &h), w+h){
        minnum = 9999;
        for (i = 1; i <= h; i++)
            for (j = 1; j <= w; j++){
                scanf("%d", &square[i][j]);
                if (square[i][j] == 2){
                    sx = i;
                    sy = j;
                }
            }
        DFS(sx, sy, 0);
        if (minnum <= 10) printf("%d\n", minnum);
        else puts("-1");
    }
    return 0;
}


2  poj3669 MeteorShower

這個題目便是BFS水題了,不過也存在很多細節問題,做這個題的時候已經很久沒刷題了,然後做題不加思考,出現了很多傻逼的錯誤…..

題意:流星雨會襲擊地球上的某些點,且毀壞這個點的同時上下左右4個點也會被毀掉。輸入給定流星雨的數量和襲擊點的座標以及時間,然後人從原點出發,必須走到不被毀壞的點才能活命,最短的逃跑時間是多少,不能逃跑輸出-1.

直接廣搜尋找最小時間就可以了,但是我犯了很多錯誤

錯誤:

1、沒有看清題意,題目說人是一定會動的,而不是一直就待在原點,所以最少花費的時間不可能為0

2、我想既然在第一象限移動,想只考慮向上或向右的狀態以去掉不必要的狀態但是這是考慮問題不到位,雖然人是一直在第一象限內運動,但一定會向上或向右運動的想法是錯誤的,可以向右再向左返回,某些情況下這樣花費的時間最少,所以在用bfs的時候也應考慮四個方向的狀態。

3、在函式內部定義大陣列,導致程式執行不能輸入也不能正常執行即結束了,這樣的大陣列為區域性變數,只能定義為全域性的。

4、沒有注意到某些流星破壞的點會有重複,所以導致其被破壞的時間為最後一個值了,對於一個點,其被破壞的時間應該是最早的那個時刻。

程式碼:

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
int dir[5][2] = {{0, 0}, {1, 0}, {-1, 0}, {0, 1}, {0, -1}};
int flag[310][310], flag1[310][310], time[310][310];
struct po
{
    int x, y, T;
    po(int a, int b, int c):x(a), y(b), T(c){}
    po():x(0), y(0), T(0){}
};
struct queue
{
    int fro, rea;
    po p[500000];
}q;

int solve()
{
    int i, T, tag = 1, x, y, ans = 0, j, M;
    scanf("%d", &M);
    memset(flag, 0, sizeof(flag));
    memset(flag1, 0, sizeof(flag1));
    memset(time, -1, sizeof(time));
    for (i = 0; i < M; i++){
        scanf("%d %d %d", &x, &y, &T);
        for (j = 0; j < 5; j++){
            int a = x+dir[j][0], b = y+dir[j][1];
            if (a>=0 && b>=0){
                if (time[a][b] >= 0) time[a][b] = min(T, time[a][b]);
                else time[a][b] = T;
                flag[a][b] = 1;
            }
        }
    }
    q.rea = q.fro = 0;
    q.p[q.rea++] = po(0, 0, 0);
    while (tag && q.fro!=q.rea){
        x = q.p[q.fro].x, y = q.p[q.fro].y;
        ans = q.p[q.fro++].T;
        if (flag[x][y] && time[x][y]<=ans) continue;
        if (!flag[x][y] && ans>0) return ans;
        for (i = 1; i < 5; i++){
            int a = x+dir[i][0], b = y+dir[i][1];
            if (a>=0 && b>=0 && !flag1[a][b]){
                q.p[q.rea++] = po(a, b, ans+1);
                flag1[a][b] = 1;
            }
        }
    }
    return -1;
}

int main()
{
    printf("%d\n", solve());
    return 0;
}

接下來換幾個稍微不同的題了:

3  hdu1254 推箱子

這個題目稍微有點意思,也讓我知道狀態轉移不是那麼想當然的或者說所謂的狀態決不能單一地判斷。題目意思我就不說了,應該都明白,這個題目相當於有兩個物體在進行狀態的變化,而且箱子在進行某一個方向的狀態變化時人必須得能夠到達箱子後面才能轉移,這個倒是能夠想到,BFS尋找擴充套件狀態,DFS判斷能否到達後面進行狀態的擴充套件,但我犯的錯誤就是在標記去重的時候沒有注意到箱子在處在某個狀態時人的狀態,直接簡單地標記點即箱子的座標,你標記狀態時必須要考慮所有的變化!!!(因為沒有考慮到這個,然後就一直WA……

程式碼:

#include <cstdio>
#include <queue>
#include <cstring>

using namespace std;
int m, n, bx, by, mx, my, tag, ex, ey;
int dir[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
int mat[10][10], f[10][10], vis[10][10][10][10];
struct po
{
    int x, y, step, sx, sy;
    po(int a, int b, int c, int d, int e):x(a), y(b), step(c), sx(d), sy(e){}
};

void check(int x, int y)
{
    if (x==ex && y==ey) tag = 0;
    if (tag){
        for (int i = 0; i<4 && tag; i++){
            int nx = x+dir[i][0], ny = y+dir[i][1];
            if (nx<1 || nx>m || ny<1 || ny>n || f[nx][ny] || mat[nx][ny]==1) continue;
            f[nx][ny] = 1;
            check(nx, ny);
        }
    }
}

int solve()
{
    queue <po> q;
    q.push(po(bx, by, 0, mx, my));
    memset(vis, 0, sizeof(vis));
    while (!q.empty()){
        po t = q.front();
        bx = t.x, by = t.y, mx = t.sx, my = t.sy, q.pop();
        if (mat[bx][by] == 3) return t.step;
        for (int i = 0; i < 4; i++){
            ex = bx-dir[i][0], ey = by-dir[i][1];
            int nx = bx+dir[i][0], ny = by+dir[i][1];
            if (nx<1 || nx>m || ny<1 || ny>n || mat[nx][ny]==1 || vis[nx][ny][ex][ey]) continue;
            if (ex<1 || ex>m || ey<1 || ey>n || mat[ex][ey]==1) continue;
            memset(f, 0, sizeof(f));
            tag = f[mx][my] = f[bx][by] = 1;
            check(mx, my);
            if (tag) continue;
            q.push(po(nx, ny, t.step+1, ex, ey));
            vis[nx][ny][ex][ey] = 1;
        }
    }
    return -1;
}

int main()
{
    int k, i, j;
    scanf("%d", &k);
    while (k--){
        scanf("%d %d", &m, &n);
        for (i = 1; i <= m; i++)
            for (j = 1; j <= n; j++){
                scanf("%d", &mat[i][j]);
                if (mat[i][j] == 2) bx = i, by = j;
                if (mat[i][j] == 4) mx = i, my = j;
            }
        printf("%d\n", solve());
    }
    return 0;
}


再來個比較相似的題目,差不多,這個就是鑰匙的變化了,不過這個有點技巧:狀態壓縮。(紫書上面所說的列舉子集便是狀態壓縮,這個還是比較不錯的,一種很好的技巧)

4HDU1429勝利大逃亡(續)

題目是中文的,就不多說了

程式碼;

#include <cstdio>
#include <queue>
#include <cstring>
#define P(x) push(x)

using namespace std;
struct po
{
    int x, y, time, bin;
    po(int a, int b, int c, int d):x(a), y(b), time(c), bin(d){}
};
int dx[] = {1, -1, 0, 0}, dy[] = {0, 0, 1, -1};
int sx, sy, T, m, n;
int vis[25][25][1<<11];
char mat[25][25];
queue<po> q;

int solve()
{
    memset(vis, 0, sizeof(vis));
    while (!q.empty()) q.pop();
    q.push(po(sx, sy, 0, 0));
    vis[sx][sy][0] = 1;
    while (!q.empty()){
        po t = q.front(); q.pop();
        int ans = t.time, b = t.bin;
        if (ans >= T) return -1;
        if (mat[t.x][t.y] == '^') return ans;
        for (int i = 0; i < 4; i++){
            int nx = t.x+dx[i], ny = t.y+dy[i], nb = b;
            if (nx>m || nx<1 || ny>n || ny<1 || vis[nx][ny][b] || mat[nx][ny]=='*') continue;
            if (mat[nx][ny]>='a' && mat[nx][ny]<='j') nb |= (1<<(mat[nx][ny]-32-'A'));
            vis[nx][ny][nb] = 1;
            if (mat[nx][ny]>='A' && mat[nx][ny]<='J'){
                if (nb & (1<<(mat[nx][ny]-'A'))) q.P(po(nx, ny, ans+1, nb));
                continue;
            }
            q.P(po(nx, ny, ans+1, nb));
        }
    }
    return -1;
}

int main()
{
    while (~scanf("%d %d %d", &m, &n, &T)){
        getchar();
        for (int i = 1; i <= m; i++){
            for (int j = 1; j <= n; j++){
                scanf("%c", &mat[i][j]);
                if (mat[i][j] == '@') sx = i, sy = j;
            }
            getchar();
        }
        printf("%d\n", solve());
    }
    return 0;
}


最後再來兩個比較有意思的題目,一個BFS,一個DFS,是我們學校隊內的個人賽題目,然而我比賽時直接卡題,一卡題腦子就蒙了,然後都沒做出來,主要是這兩個題目都不同於一般的題,不過也是大同小異,關鍵是想清楚細節才行,個人感覺還是比較好的。(我本來就是組裡面最菜的,卡題就直接悲劇了)

強烈建議可以做下這兩個題目!!!

5HDU1180 詭異的樓梯

E - 詭異的樓梯

Time Limit:1000MS     MemoryLimit:65536KB     64bitIO Format:%I64d& %I64u

Description

Hogwarts正式開學以後,Harry發現在Hogwarts,某些樓梯並不是靜止不動的,相反,他們每隔一分鐘就變動一次方向
比如下面的例子裡,一開始樓梯在豎直方向,一分鐘以後它移動到了水平方向,再過一分鐘它又回到了豎直方向.Harry發現對他來說很難找到能使得他最快到達目的地的路線,這時Ron(Harry最好的朋友)告訴Harry正好有一個魔法道具可以幫助他尋找這樣的路線,而那個魔法道具上的咒語,正是由你纂寫的

Input

測試資料有多組,每組的表述如下:第一行有兩個數,MN,接下來是一個MN列的地圖,'*'表示障礙物,'.'表示走廊,'|'或者'-'表示一個樓梯,並且標明瞭它在一開始時所處的位置:'|'表示的樓梯在最開始是豎直方向,'-'表示的樓梯在一開始是水平方向.地圖中還有一個'S'是起點,'T'是目標,0<=M,N<=20,地圖中不會出現兩個相連的梯子.Harry每秒只能停留在'.''S''T'所標記的格子內

Output

只有一行,包含一個數T,表示到達目標的最短時間
注意:Harry只能每次走到相鄰的格子而不能斜走,每移動一次恰好為一分鐘,並且Harry登上樓梯並經過樓梯到達對面的整個過程只需要一分鐘,Harry從來不在樓梯上停留.並且每次樓梯都恰好在Harry移動完畢以後才改變方向

Sample Input

5 5

**..T

**.*.

..|..

.*.*.

S....

Sample Output

7

同樣的,這個題目你在標記去重的時候不能單純地考慮到人的位置,還要考慮到此時樓梯的狀態,而且在人到達樓梯時如果能過去那麼就直接擴充套件兩步,如果不能人必須在這等待一分鐘,等樓梯變回可以通過,這個時候也可以直接擴充套件,不過此時時間+2罷了,這相當於人在這等待一分鐘然後花一分鐘再走過去。

程式碼:

#include <cstdio>
#include <queue>
#include <algorithm>
#include <cstring>

using namespace std;
struct po
{
    int x, y, time;
    po(int a, int b, int c):x(a), y(b), time(c){}
};
queue <po> q;
int m, n, sx, sy;
int dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, 1, -1};
char maze[25][25];
int vis[25][25][2];

int solve()
{
    int ans, a, b, c;
    while (!q.empty()) q.pop();
    memset(vis, 0, sizeof(vis));
    q.push(po(sx, sy, 0));
    vis[sx][sy][0] = 1;
    while (!q.empty()){
        po t = q.front(); q.pop();
        ans = t.time;
        if (maze[t.x][t.y] == 'T') return ans;
        for (int i = 0; i < 4; i++){
            a = t.x+dx[i], b = t.y+dy[i], c = ans%2;
            if (a>m || a<1 || b>n || b<1 || vis[a][b][c] || maze[a][b]=='*') continue;
            if (i>1 && ((maze[a][b]=='|' && !c) || (maze[a][b]=='-' && c))){
                b += dy[i];
                if (b>n || b<1 || vis[a][b][c] || maze[a][b]=='*') continue;
                q.push(po(a, b, ans+2));
                vis[a][b][c] = 1;
            }
            if (i<2 && ((maze[a][b]=='-' && !c) ||(maze[a][b]=='|' && c))){
                a += dx[i];
                if (a>m || a<1 || vis[a][b][c] || maze[a][b]=='*') continue;
                q.push(po(a, b, ans+2));
                vis[a][b][c] = 1;
            }
            if (i<2 && ((maze[a][b]=='|' && !c ) || (maze[a][b]=='-' && c))) a += dx[i];
            if (i>1 && ((maze[a][b]=='|' && c) || (maze[a][b]=='-' && !c))) b += dy[i];
            if (a>m || a<1 || b>n || b<1 || vis[a][b][(ans+1)%2] || maze[a][b]=='*') continue;
            q.push(po(a, b, ans+1));
            vis[a][b][(ans+1)%2] = 1;
        }
    }
    return ans;
}

int main()
{
    while (~scanf("%d %d", &m, &n)){
        getchar();
        for (int i = 1; i <= m; i++){
            for (int j = 1; j <= n; j++){
                scanf("%c", &maze[i][j]);
                if (maze[i][j] == 'S') sx = i, sy = j;
            }
            getchar();
        }
        printf("%d\n", solve());
    }
    return 0;
}


6codeforce197D Infinite Maze

最後一個DFS題了,這個題真的很特別,這個題目還是兩年前學校個人賽的題,當時也沒人做出來,這次個人賽同樣沒人做出來。不過當我看了兩年前的榜時,我佩服於那時年輕的wwdd(後面是學校ACM隊長,深得教練喜愛,已經畢業退役了),前面的50分鐘他切掉2題穩拿第一,在比賽整整的5個小時中後4個小時全部是在死磕這個題,總共錯了46次,題目測試樣例共100多組,他從第4組錯到第93組,我覺得不能做出來是正常的,因為在強大的人總有失誤的時候,但這也見證了他的執著與能力,更是體現了他在比賽時所具備的耐心與強大的心理素質。

當然這是題外話了,不過也是有感而發,下面是題目。

B - Infinite Maze

Time Limit:2000MS     MemoryLimit:262144KB     64bitIO Format:%I64d& %I64u

Description

We've gotarectangular n × m-cell maze. Eachcell is either passable,or is a wall (impassable). A little boy found the mazeand cyclically tiled aplane with it so that the plane became an infinite maze.Now on this planecell (x, y) is a wall if and only ifcell  isa wall.

In thisproblem  isaremainder of dividing number a by number b.

The littleboystood at some cell on the plane and he wondered whether he can walkinfinitelyfar away from his starting position. From cell (x, y) hecan goto one of the following cells: (x, y - 1), (x, y + 1), (x - 1, y) and (x + 1, y),provided thatthe cell he goes to is not a wall.

Input

The firstlinecontains two space-separated integers n and m (1 ≤ n, m ≤ 1500)— the heightand the width of the maze that the boy used to cyclically tile theplane.

Each ofthenext n linescontains m characters— thedescription of the labyrinth. Each character is either a "#",thatmarks a wall, a ".", that marks a passable cell, or an"S",that marks the little boy's starting point.

Thestartingpoint is a passable cell. It is guaranteed that character "S"occursexactly once in the input.

Output

Print"Yes"(without the quotes), if the little boy can walk infinitely farfrom thestarting point. Otherwise, print "No" (without the quotes).

Sample Input

Input

5 4
##.#
##S#
#..#
#.##
#..#

Output

Yes

Input

5 4
##.#
##S#
#..#
..#.
#.##

Output

No

Hint

In thefirstsample the little boy can go up for infinitely long as there is a"clearpath" that goes vertically. He just needs to repeat thefollowing stepsinfinitely: up, up, left, up, up, right, up.

In thesecondsample the vertical path is blocked. The path to the left doesn't work,too —the next "copy" of the maze traps the boy.

題目大概意思就是說給定一個圖,這個圖可以無限地向上下左右四個方向複製,也就是說當我從原圖的第一行向上走,本來是越界的,但是複製後相當於我走到了同列的最後一行,其他方向一樣的考慮,最後問能否從給定的始點S出發走一條無限的路也就是可以一直走下去。

這個題目其實仔細想想也是不難的,因為如果我沿一條路走能夠走到原來標記過的點那麼就說明我可以一直走下去了,不需要排除越界後的狀態,當我越界後便重新取餘後回到原圖,也相當於是在複製的圖中一直走,標記原圖中已經走過的狀態,當我能夠一直深搜能夠回到已經標記過的點(也即兩次座標必須不同)

剛開始做的時候考慮欠妥,想來是先從原圖中的點出發,如果後面走到的標記的點橫縱座標有一個大於原來的點時便符合,這個想必是錯的,我可以先走出去即越界這時候就不符合了,而且我最開始做的時候單純地以為圖只能往下或往右複製,其實圖可以往四周複製(某些測試樣例中必須先向上或向左走才能走無限的路),所以這樣的話我又錯了,因為出現了負數。我犯的最後一個錯就是判斷座標是否相同時我為了簡單起見,判斷和是否相同,然而我特地去CF上跑一遍以找到錯誤的樣例,發現錯誤情況中剛好兩個座標和相同卻又能走無限的路….

綜合以上考慮,直接從始點出發,一直深搜,如果越界便通過取餘的技巧回到原圖(這是為了好判斷越界後圖的情況),如果走到已經標記過的點且座標不同的話便證明可以走無限的路了。

程式碼:

(其實我的程式碼還是很挫的(239720kb1528ms),差點就MLETLE了,很多人都比我寫的好,時間空間少了很多很多,可以去找更好的程式碼以參考)

#include <cstdio>
#include <cstring>
#include <vector>

using namespace std;
struct po
{
    int x, y;
    po(int a, int b):x(a), y(b){}
};
int n, m, sx, sy, tag = 1;
char maze[1510][1510];
vector<po> vis[1510][1510];
int dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, 1, -1};

void solve(int x, int y)
{
    if (tag){
        for (int i = 0; i<4 && tag; i++){
            int nx = x+dx[i], ny = y+dy[i];
            int a = (nx%n+n)%n?(nx%n+n)%n:n, b = (ny%m+m)%m?(ny%m+m)%m:m;
            if (maze[a][b]=='#') continue;
            if (vis[a][b].size()){
                if(vis[a][b][0].x!=nx || vis[a][b][0].y!=ny){
                    tag = 0;
                }
                else continue;
            }
            else vis[a][b].push_back(po(nx, ny));
            solve(nx, ny);
        }
    }
}

int main()
{
    scanf("%d %d", &n, &m);
    getchar();
    for (int i = 1; i <= n; i++){
        for (int j = 1; j <= m; j++){
            scanf("%c", &maze[i][j]);
            if (maze[i][j] == 'S') sx = i, sy = j;
        }
        getchar();
    }
    memset(vis, 0, sizeof(vis));
    vis[sx][sy].push_back(po(sx, sy));
    solve(sx, sy);
    tag?puts("No"):puts("Yes");
    return 0;
}

最後,我試了試把vector換成陣列以比較STL模板容器和自定義容器的區別,結果真的就MLE了,看來vector還真是好用………..

我想說的最後一句話就是刷題一定不能想當然,首先需要考慮仔細再下手,真的說各種樣例來測你的程式碼難免會出現錯誤的情況,而且做題之前一定要把題目看清,我很多題目都因為是英文題沒注意細節,然後無盡的WA

關於DFSBFS就講到這裡,希望我的總結對你有幫助<(^-^)>