ランダムDFS木/DFSパス
概要
- グラフやグリッドなどで、なんらかの木構造を作りたいとき、サイクルができないようにランダムにDFSで訪問すると、ランダムなパスや木構造が得られる
コード(ランダムDFS木生成)
- グリッド上での迷路生成
- dfsで「1つ前に行った方向、連続で選んでいる回数」なども引数で渡すと、条件を満たすDFS木を生成できる
constexpr static int vy[4] = {-1, 0, 1, 0};
constexpr static int vx[4] = {0, -1, 0, 1};
bool in_range(int N, const P& p) {
return 0 <= p.y && p.y < N && 0 <= p.x && p.x < N;
}
void dfs(int N, vector<vector<int>>& v, const P& p) {
v[p.y][p.x] = 1;
vector<int> order{0, 1, 2, 3};
xor128_shuffle(order.begin(), order.end());
for (int k : order) {
P nxt(p.y + vy[k], p.x + vx[k]);
if (!in_range(N, nxt)) continue;
if (v[nxt.y][nxt.x] == 1) continue;
// サイクルができるかチェック
bool ok = true;
rep(kk, 4) {
P adj(nxt.y + vy[kk], nxt.x + vx[kk]);
if (!in_range(N, adj)) continue;
if (adj == p) continue;
if (v[adj.y][adj.x] == 1) ok = false;
}
if (ok) dfs(N, v, nxt);
}
}
vector<vector<int>> make_random_dfs_tree(int N, const P& start) {
vector<vector<int>> v(N, vector<int>(N, 0));
dfs(N, v, start);
return v;
}
int main() {
int N = 10;
auto v = make_random_dfs_tree(N, P(N/2, 0));
rep(y, N) {
rep(x, N) {
cout << (v[y][x] == 1 ? "*" : " ");
}
cout << endl;
}
return 0;
}
コード(ランダムDFSパス)
- グリッド上で、2頂点をつなぐランダムなパスを生成
- パスの部分破壊再構築近傍などで利用
constexpr static int vy[4] = {-1, 0, 1, 0};
constexpr static int vx[4] = {0, -1, 0, 1};
bool in_range(int N, const P& p) {
return 0 <= p.y && p.y < N && 0 <= p.x && p.x < N;
}
int dfs_max_len; // パスの長さ制限
int dfs_count; // dfsの呼び出し回数制限(見つからない場合は失敗扱いにする)
vector<P> dfs_path; // 見つけたパス
bool dfs(int N, vector<vector<int>>& v, const P& p, const P& goal) {
if (dfs_path.size() > dfs_max_len) return false;
if (dfs_count == 0) return false;
dfs_count--;
if (p == goal) {
return true;
}
v[p.y][p.x] = 1;
vector<int> order{0, 1, 2, 3};
xor128_shuffle(order.begin(), order.end());
for (int k : order) {
P nxt(p.y + vy[k], p.x + vx[k]);
if (!in_range(N, nxt)) continue;
if (v[nxt.y][nxt.x] == 1) continue;
dfs_path.emplace_back(nxt);
if (dfs(N, v, nxt, goal)) return true;
if (dfs_count == 0) return false;
dfs_path.pop_back();
}
v[p.y][p.x] = 0;
return false;
}
bool make_random_dfs_path(int N, int max_len, const P& start, const P& goal) {
vector<vector<int>> v(N, vector<int>(N, 0));
dfs_max_len = max_len;
dfs_count = 1000;
dfs_path.clear();
dfs_path.emplace_back(start);
return dfs(N, v, start, goal);
}
int main() {
rep(i, 10) { // 10回ランダムにパスを生成
// NxNのグリッドの左真ん中から右真ん中に向かってパスを生成
const int N = 5;
make_random_dfs_path(N, 10, P(N / 2, 0), P(N / 2, N - 1));
vector<vector<int>> v(N, vector<int>(N, -1));
rep(j, dfs_path.size()) v[dfs_path[j].y][dfs_path[j].x] = j;
cout << "--------" << endl;
rep(y, N) {
rep(x, N) {
if (v[y][x] == -1) {
cout << ".";
} else {
cout << v[y][x];
}
}
cout << endl;
}
}
return 0;
}
Verified