DFS是被廣泛運用的搜索算法,它屬於一種盲目搜索,定義如下:
1、起始訪問的頂點是指定的;
2、若當前訪問的頂點的鄰接頂點有未被訪問的,則任選一個訪問;反之,退回到最近訪問過的頂點;直到與起始頂點相通的全部頂點都訪問完畢;
3、若此時圖中尚有頂點未被訪問,則再選其中一個頂點作爲起始頂點並訪問之,轉 2; 反之,遍歷結束。
大多數時候我們用dfs時會採用遞歸的方式,但是非遞歸的方式更加直觀,思路更清晰,更便於我們去理解”深度“的思想。這篇文章主要介紹如何用unity引擎來可視化模擬非遞歸的dfs算法。爲了方便理解,給出一個經典的紅黑格題目,要求如下:
有一個長方形的房間,房間裏的地面上佈滿了正方形的瓷磚,瓷磚要麼是紅色的,要麼是黑色的。一個人站在其中一塊黑色的瓷磚上,他可以向四周的瓷磚上移動,但是不能移動到紅色的瓷磚上,只能在黑色的瓷磚上移動,用深度優先搜索的思想模擬該過程。
輸入數據有三個,分別是房間的長和寬,以及一個字符串。字符串含有房間中磚塊的顏色信息,例如“#”表示黑色瓷磚,“*”表示紅色瓷磚,“@”表示該位置的黑色瓷磚,那麼字符串可以是
"***#**######@#***##**#***##***#***#****##*###*#**"
(注意,長和寬的乘積應該和字符串字符數相同。)
腳本代碼如下(c#):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
using System;
using UnityEditor;
public class NewBehaviourScript : MonoBehaviour
{
public GameObject redcube, blackcube, yellowcube, origncube, Ethan;
public string Str1;
public int weight, height;
private int k = 0;
public char[,] map;
public int[] path;//記錄走過的座標
private int[] dx = { 1, -1, 0, 0 }, dy = { 0, 0, 1, -1 };
public int[,] visited;//記錄每一塊磚走過的次數
private int cnt = 0, row = 0, cnt2 = 0;
private int sx = 0, sy = 0;
public float time = 0;
private bool moved = false, isbacking = false, once = false;
private float deltaposxy = 4.2f, deltaposz = 0.27f;
void Start()
{
//初始化map 生成地圖
Transform temp = transform;
temp.position = new Vector3(orign.transform.position.x, 0, orign.transform.position.z);
visited = new int[weight, height];
map = new char[weight, height];
path = new int[weight * height * 100];
for (int j = 0; j < height; j++)
{
for (int i = 0; i < weight; i++)
{
if (Str1[k] == '*')
{
map[i, j] = Str1[k];
temp.position = new Vector3(orign.transform.position.x + i * deltaposxy, 0, orign.transform.position.z + j * deltaposxy);
GameObject ared = Instantiate(red, temp.position, temp.rotation);
k++;
continue;
}
if (Str1[k] == '#')
{
map[i, j] = Str1[k];
temp.position = new Vector3(orign.transform.position.x + i * deltaposxy, 0, orign.transform.position.z + j * deltaposxy);
GameObject ablack = Instantiate(black, temp.position, temp.rotation);
k++;
continue;
}
if (Str1[k] == '@')
{
map[i, j] = Str1[k];
sx = i; sy = j;
temp.position = new Vector3(orign.transform.position.x + i * deltaposxy, 0, orign.transform.position.z + j * deltaposxy);
GameObject ayellow = Instantiate(yellow, temp.position, temp.rotation);
k++;
continue;
}
}
}
k = 0;
gameObject.transform.position = new Vector3(orign.transform.position.x + sx * deltaposxy, deltaposz, orign.transform.position.z + sy * deltaposxy);
dfs();
}
private int j = 0;
void Update()
{
time++;
if (time % 30 == 0)
{
if (cnt2 > 0)
{
Transform temp = transform;
temp.position = new Vector3(orign.transform.position.x + path[j] * deltaposxy, deltaposz, orign.transform.position.z + path[j + 1] * deltaposxy);
GameObject aethan = Instantiate(Ethan, temp.position, temp.rotation);
j += 2;
Destroy(aethan, 0.35f);
cnt2--;
}
}
}
void dfs()
{
visited[sx, sy] = 1;//標記1表示Ethan走過此磚一次
cnt++;
while (true)
{
for (int i = 0; i < 4; i++)
{
int nx = sx + dx[i], ny = sy + dy[i];//前後左右選擇一個方向判斷
if (nx >= 0 && nx < weight && ny >= 0 && ny < height)
{
if (visited[nx, ny] == 0 && map[nx, ny] != '*')//找到了某一方向有從未走過的磚,前進
{
path[row] = nx; row++;
path[row] = ny; row++;
moved = true;
//在返回的途中發現沒走過的磚,將現在腳下拐彎的磚標記爲1(原本應該標記爲2),因爲後面一定還會至少再經過一次
if (isbacking == true) visited[sx, sy] = 1; //
isbacking = false;
sx = nx; sy = ny;
visited[sx, sy] = 1;//將走過一次的磚標記爲1
cnt++;
cnt2++;
time = 0;
break;
}
}
}
if (moved == true)
{
moved = false;
continue;
}
//前後左右都不存在沒走過的磚,此時找走過一次的磚
for (int i = 0; i < 4; i++)
{
int nx = sx + dx[i], ny = sy + dy[i];//前後左右選擇一個方向判斷
if (nx >= 0 && nx < weight && ny >= 0 && ny < height)
{
if (visited[nx, ny] == 1 && map[nx, ny] != '*')//找到了某一方向有走過一次的磚,前進
{
path[row] = nx; row++;
path[row] = ny; row++;
moved = true;
sx = nx; sy = ny;
visited[sx, sy] = 2;//將走過兩次的磚標記爲2
isbacking = true;
time = 0;
cnt2++;
break;
}
}
}
if (moved == true)
{
moved = false;
continue;
}
Debug.Log(cnt);
break;
}
}
}
將此腳本掛在一個空物體上,並在unity中給腳本的每一個數據成員賦上初始值,點擊開始就可以開到模擬出的dfs算法思路。效果如下:
謝謝觀看:)