C#でチェスのナイトが目的地に到達するまでの最小ステップ数を求める方法
本記事では、チェスのナイト(騎士)が盤上のすべてのマスを訪れ、かつ同じマスは一度しか通れないという条件で移動する「ナイト・ツアー」の考え方と、始点から目的地までの最小ステップ数をC#で求める方法について解説します。
ナイト・ツアーの種類
ナイトの移動には、完了時の形によって2つのタイプがあります。
- 閉路ツアー(Closed Tour):最後にスタート地点からナイトの1手で戻れる位置に到達し、閉じたループを形成するツアー。
- 開放ツアー(Open Tour):スタート地点に戻らず、盤上の任意の場所で終了するツアー。
有効な移動とは、移動先が盤面の内側にあり、かつそのマスがまだ訪問されていないことを指します。実装では、未訪問のセルをすべて -1 で初期化し、訪問済みかどうかを管理します。
最小ステップ数を求めるアルゴリズム
始点から目的地までの最短手数を求める場合、幅優先探索(BFS)を利用するのが定石です。BFSは近いマスから順に探索を広げていくため、目的地に最初に到達した時点での手数が必ず最小となります。以下のサンプルコードでは、30×30の盤面上でナイトが座標 (1, 1) から (30, 30) へ移動するケースを扱っています。
処理の流れ
- 始点の座標と距離0をキューに追加します。
- キューからセルを取り出し、目的地であればその時点の距離を返します。
- ナイトが移動できる8方向(dx・dy の組み合わせ)について、盤内かつ未訪問のセルだけをキューに追加します。
- これを繰り返し、目的地に到達した時点の手数を出力します。
C#による実装例
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
namespace ConsoleApplication{
public class KnightWalkProblem{
public class cell{
public int x, y;
public int dis;
public cell(int x, int y, int dis){
this.x = x;
this.y = y;
this.dis = dis;
}
}
static bool isInside(int x, int y, int N){
if (x >= 1 && x <= N && y >= 1 && y <= N)
return true;
return false;
}
public int minStepToReachTarget(int[] knightPos, int[] targetPos, int N){
int[] dx = { -2, -1, 1, 2, -2, -1, 1, 2 };
int[] dy = { -1, -2, -2, -1, 1, 2, 2, 1 };
Queue<cell> q = new Queue<cell>();
q.Enqueue(new cell(knightPos[0], knightPos[1], 0));
cell t;
int x, y;
bool[] visit = new bool[N + 1, N + 1];
for (int i = 1; i <= N; i++)
for (int j = 1; j <= N; j++)
visit[i, j] = false;
visit[knightPos[0], knightPos[1]] = true;
while (q.Count != 0){
t = q.Peek();
q.Dequeue();
if (t.x == targetPos[0] && t.y == targetPos[1])
return t.dis;
for (int i = 0; i < 8; i++){
x = t.x + dx[i];
y = t.y + dy[i];
if (isInside(x, y, N) && !visit[x, y]){
visit[x, y] = true;
q.Enqueue(new cell(x, y, t.dis + 1));
}
}
}
return int.MaxValue;
}
}
class Program{
static void Main(string[] args){
KnightWalkProblem kn = new KnightWalkProblem();
int N = 30;
int[] knightPos = { 1, 1 };
int[] targetPos = { 30, 30 };
Console.WriteLine(
kn.minStepToReachTarget(
knightPos,
targetPos, N));
}
}
}
出力結果
20
このコードを実行すると「20」と出力されます。これは、30×30の盤面上でナイトが左上の (1, 1) から右下の (30, 30) に到達するために必要な最小手数を表しています。計算量は盤面のマス数に対して線形であり、BFSにより常に最短経路が保証されるのが大きな特徴です。
-
Pythonプログラム:ベビーステップとジャイアントステップで目的地に到達するための最小ステップ数を求める
問題の概要クエリのリスト Q が与えられ、各クエリ Q[i] は [a_i, b_i, d_i] という3つの値から構成されているとします。初期位置は (0, 0) であり、1ステップごとに、現在位置 (x1, y1) から2点間のユークリッド距離が a 以上 b 以下となる任意の点 (x2, y2) へ移動できます。各クエリに対して、(0, 0) から (d_i, 0) へ到達するために必要な最小ステップ数を求めるのがこの問題の目的です。たとえば、入力が Q = [(2,3,1), (1,2,0), (3,4,11)] の場合、出力は [2, 0, 3] となります。その理由は以下の通りです
-
Pythonで数値の階乗を求める方法を解説!forループとrange関数の使い方
階乗(factorial)とは、1からその数までのすべての整数を掛け合わせた積のことです。例えば、5の階乗は「5 × 4 × 3 × 2 × 1 = 120」となります。 Pythonで指定した数の階乗を求めるには、range()関数を使って1からその数まで繰り返すforループを作成します。ここで注意すべき点は、range()関数は終了値(ストップ値)を含まないという仕様です。そのため、終了値は入力された数値より1大きい値(num+1)を指定する必要があります。 階乗を求めるPythonコードの例 ループ内では、各数値を変数 f に累積的に掛けていきます。この変数 f は初期値として 1 を設