1. 程式人生 > 其它 >紅與黑[DFS]

紅與黑[DFS]

技術標籤:每天演算法演算法dfs

紅與黑[DFS]

文章目錄

題目描述

有一間長方形的房子,地上鋪了紅色、黑色兩種顏色的正方形瓷磚。

你站在其中一塊黑色的瓷磚上,只能向相鄰(上下左右四個方向)的黑色瓷磚移動。

請寫一個程式,計算你總共能夠到達多少塊黑色的瓷磚。

輸入格式

輸入包括多個數據集合。

每個資料集合的第一行是兩個整數 WW 和 HH,分別表示 xx 方向和 yy 方向瓷磚的數量。

在接下來的 HH 行中,每行包括 WW 個字元。每個字元表示一塊瓷磚的顏色,規則如下

1)‘.’:黑色的瓷磚;
2)‘#’:紅色的瓷磚;

3)‘@’:黑色的瓷磚,並且你站在這塊瓷磚上。該字元在每個資料集合中唯一出現一次。

當在一行中讀入的是兩個零時,表示輸入結束。

輸出格式

對每個資料集合,分別輸出一行,顯示你從初始位置出發能到達的瓷磚數(記數時包括初始位置的瓷磚)。

資料範圍

1≤W,H≤201≤W,H≤20


6 9 
....#. 
.....# 
...... 
...... 
...... 
...... 
...... 
#@...# 
.#..#. 
0 0

輸出樣例:

45

思路分析

  • 應題目要求,我們只能找到,‘@’與其他黑磚相連的區域,並記錄黑磚的個數就是答案。

  • 首先分析,每次座標變換的偏移量, 以下圖為例分析。

    • 在這裡插入圖片描述

    • 由題可知,每次移動只能向上下左右移動一個瓷磚,所以和以得到,x軸和y軸的偏移量,**注意:**這裡說的 x軸 指的是——以左上交為原點,向下為 x正半軸,向右為 y軸負半軸。

    • 得到 x和y軸的偏移量,可以存在陣列中(方便計算相鄰的點)。

  • 演算法

    • 本題用到了深度優先搜尋,簡稱DFS。
      • 深度優先搜尋就是,先選中一條路徑一直走,走到底,然後沒路了,返回上一個交叉口(選擇的地方),走其他的路徑,也就是嘗試求出每種結果找出正確答案。
      • 本題,就是一個簡單的dfs求連通區域。首先,由題可知每個瓷磚只能計算一次,所以需要用一個 標記 陣列, 來記錄當前瓷磚是否已經計算過了。最後得到的就是答案。

AC程式碼

java程式碼

import java.util.Scanner;

public class Main {
    public static int[] dx = {-1, 1, 0, 0}; // x軸偏移量
    public static int[] dy = {0, 0, -1, 1}; // y軸偏移量
    public static int ans = 0;
    public static int n = 0;
    public static int m = 0;
    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in);

            while (true) {
                m = cin.nextInt();
                n = cin.nextInt();
                if (n == 0 && m == 0) break;
                ans = 0;
                cin.nextLine();
                boolean[][] v = new boolean[n][m]; // 定義標記陣列
                StringBuilder[] mp = new StringBuilder[n]; // 儲存輸入的地圖

                int x = 0, y = 0, f = -1;
                for (int i = 0; i < n; ++ i) {
                    mp[i] = new StringBuilder(cin.nextLine());
                    f = mp[i].indexOf("@"); 
                    if (f != -1) { // 找到開始位置
                        x = i;
                        y = f;
                    }
                }
                dfs(x, y, v, mp); // 進行深度優先搜尋

                System.out.println(ans);
            }
    }
    public static void dfs(int x, int y, boolean[][] v, StringBuilder[] mp) {
        v[x][y] = true; // 標記當前,x,y座標的函式已經計算過了
        ans ++;// 加入答案
        for (int i = 0; i < 4; ++ i) { // 判斷當前黑瓷磚周圍的其他磚
            int nx = x + dx[i];
            int ny = y + dy[i];
            // 判斷 座標是否超過陣列大小,判斷當前瓷磚是否記錄過,判斷當前周邊瓷磚是否為黑瓷磚
            if (nx < 0 || nx >= n || ny < 0 || ny >= m || v[nx][ny] == true || mp[nx].charAt(ny) == '#') continue;
            dfs(nx, ny, v, mp);// 是黑瓷磚,且沒越界,沒計算過,則繼續以當前瓷磚為點,選中它周圍的瓷磚,進行搜尋

        }
    }
}

C++程式碼

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 25;
int dx[] = {0, 0, -1, 1};
int dy[] = {1, -1, 0, 0};
int n, m, ans = 0;
bool v[N][N];
char mp[N][N];

void dfs(int x, int y) {
    v[x][y] = true;
    ans ++;
    for (int i = 0; i < 4; ++ i) {
        int nx = x + dx[i];
        int ny = y + dy[i];
        if (nx < 0 || nx >= n || ny < 0 || ny >= m || v[nx][ny] == true || mp[nx][ny] == '#') continue;
        dfs(nx, ny);
    }
}

int main () {
    
    while (true) {
        cin >> m >> n;
        if (n == 0 && m == 0) break;
        ans = 0;
        memset(v, 0, sizeof v);
        int x, y;
        for (int i = 0; i < n; ++ i) {
            for (int j = 0; j < m; ++ j) {
                cin >> mp[i][j];
                if (mp[i][j] == '@') x = i, y = j;
            }
        }
        
        dfs(x, y);
        cout << ans << endl;
    }
    
    return 0;
}