天天看點

廣度優先搜尋C++算法習題練習

因為本文章是習題練習,所有不會有具體講解。如想看具體的思路講解,請在我的部落格中找到廣度優先搜尋算法帶圖詳解, 或者通路

廣度優先搜尋算法帶圖詳解_不怕困難的部落格的部落格-CSDN部落格

問題 A: 【一本通基礎廣度優先搜尋】 最少步數

[題目描述]

在各種棋中,一種棋子的走法總是一定的,如中國象棋中馬走“日”。有一位國小生就想如果馬能有兩種走法将更加增加趣味性,是以,他規定馬既能按“日”飛,也能各象一樣走“田”字。他的同桌平時喜歡下圍棋,知道這件事後覺得很有趣,就和他玩一種新遊戲,在圍棋盤上任選兩點A、B,A點放上黑子,B點放上白子,代表兩匹馬。棋子可以按“日”字走,也可以按“田”字走,倆人一個走黑馬,一個走白馬。誰用最少的步數走到左上角坐标為(1,1)的點時,誰獲勝。現在他請你幫忙,給你A,B兩點的坐标,想知道兩個位置到(1,1)點的可能最少步數。

輸入

每行的兩個整數,第一行為A點坐标

第二行為B點坐标

(* 注意:棋盤大小規模為100*100以内 *)

輸出

兩行第一行為A點到(1,1)的步數

第二行為B點到(1,1)的步數

樣例輸入

12 16
18 10
      

樣例輸出

8
9      

代碼:

#include <bits/stdc++.h>
using namespace std;
 
int dx[12] = {-2, -2, -1, 1, 2, 2, 2, 2, 1, -1, -2, -2};
int dy[12] = {-1, -2, -2, -2, -2, -1, 1, 2, 2, 2, 2, 1};
 
int main()
{
    int s[101][101], que[10000][4] = {0}, x1, x2, y1, y2;
    memset(s, 0xff, sizeof((s)));//s數組的初始化 
    int head = 1, tail = 1;//初始位置入隊列 
    que[1][1] = 1;
    que[1][2] = 1;
    que[1][3] = 0;
    cin >> x1 >> y1 >> x2 >> y2;//讀入黑馬和白馬的位置 
    while(head <= tail)//如果隊列為空, 則拓展隊首結點 
    {
        for(int i = 0; i <= 11; i++)//枚舉12個拓展方向 
        {
            int x = que[head][1] + dx[i];
            int y = que[head][2] + dy[i];
            if(x > 0 && y > 0 && x <= 100 && y <= 100)
            {
                if(s[x][y] == -1)
                {
                    s[x][y] = que[head][3] + 1;
                    tail++;//(1, 1)到(x,y)的最小步數入隊 
                    que[tail][1] = x;
                    que[tail][2] = y;
                    que[tail][3] = s[x][y];
                    if(s[x1][y1] > 0 && s[x2][y2] > 0)//輸出答案 
                    {
                        cout << s[x1][y1] << endl;
                        cout << s[x2][y2] << endl;
                        return 0;
                    }
                }
            }
        }
        head++;
    }
    return 0;
} 
           

問題 B: 【一本通基礎廣度優先搜尋】The Castle

【題目描述】

一座城堡被分成m*n個方塊(m≤50,n≤50),每個方塊可有0~4堵牆(0表示無牆)。下面示出了建築平面圖:

廣度優先搜尋C++算法習題練習

圖中的加粗黑線代表牆。幾個連通的方塊組成房間,房間與房間之間一定是用黑線(牆)隔開的。

現在要求你編一個程式,解決以下2個問題:

1、該城堡中有多少個房間?

2、最大的房間有多大?

【輸入】

平面圖用一個數字表示一個方塊(第1個房間用二進制1011表示,0表示無東牆,用十進制11表示)。

第一行一個整數m(m≤50),表示房子南北方向的長度。

第二行一個整數n(n≤50),表示房子東西方向的長度。

後面的m行,每行有n個整數,每個整數都表示平面圖對應位置的方塊的特征。每個方塊中牆的特征由數字P來描述(0≤P≤15)。數字P是下面的可能取的數字之和:

1(西牆 west)

2(北牆 north)

4(東牆 east)

8(南牆 south)

室内的牆被定義兩次: 例如方塊(1,1)中的南牆也被位于其南面的方塊(2,1)定義了一次。

建築中至少有兩個房間。

【輸出】

第1行:一個整數,表示房間總數;

第2行:一個整數,表示最大房間的面積(方塊數)。

【輸入樣例】

4
7
11 6 11  6  3 10  6
7  9  6 13  5 15  5
1 10 12  7 13  7  5
13 11 10 8 10 12 13
      

【輸出樣例】

5
9      
#include <bits/stdc++.h>
using namespace std;
 
int dx[4] = {-1, 1, 0, 0};
int dy[4] = {0, 0, -1, 1};
int a[51][51][4], q[5001][3];
int tot, i, j, p, n, m, maxx = -1;
bool b[51][51];
 
void bfs(int x, int y)
{
    memset(q, 0, sizeof(q));
    tot++;
    int head = 0, tail = 1, xx, yy;
    q[1][1] = x;
    q[1][2] = y;
    b[x][y] = false;
    int cnt = 1;
    while(head < tail)
    {
        head++;
        for(int i = 0; i <= 3; i++)
        {
            xx = q[head][1] + dx[i];
            yy = q[head][2] + dy[i];
            if((xx > 0) && (xx <= m) && (yy > 0) && (yy <= n) && (b[xx][yy]) && a[q[head][1]][q[head][2]][i] == 0)
            {
                tail++;
                cnt++;
                b[xx][yy] = false;
                q[tail][1] = xx;
                q[tail][2] = yy;
            }
        }
    }
    maxx = max(cnt, maxx);
}
 
int main()
{
    memset(b, true, sizeof(b));
    scanf("%d %d", &m, &n);
    for(int i = 1; i <= m; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            scanf("%d", &p);
            if(p >= 8)
            {
                p -= 8;
                a[i][j][1] = 1;
            }
            if(p >= 4)
            {
                p -= 4;
                a[i][j][3] = 1;
            }
            if(p >= 2)
            {
                p -= 2;
                a[i][j][0] = 1;
            }
            if(p >= 1)
            {
                p -= 1;
                a[i][j][2] = 1;
            }
        }
    }
    for(int i = 1; i <= m; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            if(b[i][j])
            {
                bfs(i, j);
            }
        }
    }
    printf("%d\n%d\n", tot, maxx);
    return 0;
}
           

問題 C: 【一本通基礎廣度優先搜尋】Lake Counting 數池塘

[題目描述]

 農夫約翰的農場可以表示成N×M(1≤N,M≤100)個方格組成的矩形.由于近日的降雨,

在約翰農場上的不同地方形成了池塘.每一個方格或者有積水(’W’)或者沒有積水(’.’).農夫約翰打算數出他的農場上共形成了多少池塘.一個池塘是一系列相連的有積水的方格,每一個方格周圍的八個方格都被認為是與這個方格相連的.

    現給出約翰農場的圖樣,要求輸出農場上的池塘數.

輸入

 第1行:由空格隔開的兩個整數N和M.

 第2到N+1行:每行M個字元代表約翰農場的一排方格的狀态.每個字元或者是’W’或者

是’.’,字元之間沒有空格.

輸出

約翰農場上的池塘數.

樣例輸入

10 12
W ........ WW.
. WWW ..... WWW
.... WW ... WW.
......... WW.
......... W..
..W ...... W..
.W.W ..... WW.
W.W.W ..... W.
.W.W ...... W.
..W ....... W.
      

樣例輸出

3      
#include <bits/stdc++.h>
using namespace std;
 
int dx[8] = {-1, -1, 0, 1, 1, 1, 0, -1};
int dy[8] = {0, 1, 1, 1, 0, -1, -1, -1};
int n, m;
int ans = 0;
int h[10001][3];
char map1[101][101];
 
void js(int p, int q)
{
    memset(h, 0, sizeof(h));
    int x, y, head = 0, tail = 1;
    ans++;
    h[1][1] = p;
    h[1][2] = q;
    map1[p][q] = '.';
    do
    {
        head++;
        for(int i = 0; i < 8; i++)
        {
            x = h[head][1] + dx[i];
            y = h[head][2] + dy[i];
            if(x > 0 && x <= n && y > 0 && y <= m && map1[x][y] == 'W')
            {
                map1[x][y] = '.';
                tail++;
                h[tail][1] = x;
                h[tail][2] = y;
            }
        }
    }while(head < tail);
}
 
int main()
{
    cin >> n >> m;
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            cin >> map1[i][j];
        }
    }
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            if(map1[i][j] == 'W')
            {
                js(i, j);
            }
        }
    }
    cout << ans << endl;
    return 0;
}
           

問題 D: 【一本通基礎廣度優先搜尋】走迷宮

[題目描述]

一個迷宮由R行C列格子組成,有的格子裡有障礙物,不能走;有的格子是空地,可以走。

給定一個迷宮,求從左上角走到右下角最少需要走多少步(資料保證一定能走到)。隻能在水準方向或垂直方向走,不能斜着走。

輸入

第一行是兩個整數,R和C,代表迷宮的長和寬。( 1≤ R,C ≤ 40)

接下來是R行,每行C個字元,代表整個迷宮。

空地格子用‘.’表示,有障礙物的格子用‘#’表示。

迷宮左上角和右下角都是‘.’。

輸出

輸出從左上角走到右下角至少要經過多少步(即至少要經過多少個空地格子)。計算步數要包括起點和終點。

樣例輸入

5 5
..###
#....
#.#.#
#.#.#
#.#..      

樣例輸出

9      
#include <bits/stdc++.h>
using namespace std;
int xx[4] = {-1, 1, 0, 0};
int yy[4] = {0, 0, -1, 1};
int h[1001][5];
bool a[41][41];
int r, c, x, y;
char k;
int head, tail, i;
int main()
{
    cin >> r >> c;
    for(int i = 1; i <= r; i++)
    {
        for(int j = 1; j <= c; j++)
        {
            cin >> k;
            if(k == '.') a[i][j] = true;
            else a[i][j] = false;
        }
    }
//  for(int i = 1; i <= r; i++)
//  {
//      for(int j = 1; j <= c; j++)
//      cout << a[i][j] << " ";
//      cout << endl;
//  }
    head = 0;
    tail = 1;
    h[1][1] = 1;
    h[1][2] = 1;
    h[1][3] = 1;
    while(head < tail)
    {
        head++;
        for(int i = 0; i < 4; i++)
        {   
            x = h[head][1] + xx[i];
            y = h[head][2] + yy[i];
            if((x > 0) && (x <= r) && (y > 0) && (y <= c) && (a[x][y] == true))
            {
                tail++;
                h[tail][1] = x;
                h[tail][2] = y;
                h[tail][3] = h[head][3] + 1;
                a[x][y] = false;
                if(x == r && y == c)
                {
                    cout << h[tail][3] << endl;
                    return 0;
                }
            }
        }
         
    }
    return 0;
}
           

問題 E: 【一本通基礎廣度優先搜尋】走出迷宮

[題目描述]

當你站在一個迷宮裡的時候,往往會被錯綜複雜的道路弄得失去方向感,如果你能得到迷宮地圖,事情就會變得非常簡單。

假設你已經得到了一個n*m的迷宮的圖紙,請你找出從起點到出口的最短路。

輸入

第一行是兩個整數n和m(1≤n,m≤100),表示迷宮的行數和列數。

接下來n行,每行一個長為m的字元串,表示整個迷宮的布局。字元‘.’表示空地,‘#’表示牆,‘S’表示起點,‘T’表示出口。

輸出

輸出從起點到出口最少需要走的步數。

樣例輸入

3 3
S#T
.#.
...
      

樣例輸出

6
      
#include <bits/stdc++.h>
using namespace std;
int h[1004][4];
int xx[4] = {-1, 1, 0, 0},
    yy[4] = {0, 0, -1, 1};
bool a[101][101];
int main()
{
    int n, m, fx, fy, x, y, t, w;
    char c;
    memset(a, true, sizeof(a));
    cin >> n >> m;
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            cin >> c;
            if(c == 'S')
            {
                h[1][1] = i;
                h[1][2] = j;
                h[1][3] = 0;
                a[i][j] = false;
            }
            else if(c == 'T')
            {
                fx = i;
                fy = j;
            }
            else if(c == '#') a[i][j] = false;
             
        }
    }
    t = 0, w = 1;
    do
    {
        t++;
        for(int i = 0; i < 4; i++)
        {
            x = h[t][1] + xx[i];
            y = h[t][2] + yy[i];
            if(x > 0 && x <= n && y > 0 && y <= m &&a[x][y])\
            {
                a[x][y] = false;
                w++;
                h[w][1] = x;
                h[w][2] = y;
                h[w][3] = h[t][3] + 1;
                if(x == fx && y == fy)
                {
                    cout << h[w][3] << endl;
                    return 0;
                }
            }
        }
    }while(t < w);
}
           

繼續閱讀