Cプログラミング
 Computer >> コンピューター >  >> プログラミング >> Cプログラミング

行列内確率問題:N回移動後にマトリクス内に留まる確率をDFSで計算する方法

問題の概要

今回は行列(マトリクス)に関する確率問題を取り上げます。長方形の行列が与えられ、現在のセルからは上下左右の4方向へ等しい確率で移動できるものとします。このとき、位置 M[i, j] から N 回移動した後に、行列の内側に留まっている確率を求めるのが目的です。

解法のアプローチ:DFSを活用

この問題は、深さ優先探索(DFS)の考え方を使って解くことができます。具体的には、現在のセルから移動可能な4方向それぞれに対して再帰的に探索を行い、残りの移動回数を1ずつ減らしながら確率を計算していきます。

4つの方向の移動確率はすべて等しいため、各方向は全体の確率に対して 0.25 ずつ寄与します。再帰の過程で行列の境界を越えた場合は 0 を返し、N 回の移動が完了した時点では 1 を返します。これらを合計することで、求める確率が得られます。

アルゴリズム

matProb(m, n, x, y, N)

Begin
    if (x, y) が行列 m×n の境界外であれば 0 を返す
    if N が 0 であれば 1 を返す
    prob := 0
    prob := prob + matProb(m, n, x-1, y, N-1) * 0.25
    prob := prob + matProb(m, n, x+1, y, N-1) * 0.25
    prob := prob + matProb(m, n, x, y+1, N-1) * 0.25
    prob := prob + matProb(m, n, x, y-1, N-1) * 0.25
    return prob
End

C++による実装例

#include<iostream>
using namespace std;

// (x, y) が行列内にあるかどうかを判定する関数
bool isSafe(int x, int y, int m, int n) {
    if(x >= 0 && x < m && y >= 0 && y < n){
        return true;
    }
    return false;
}

double matProb(int m, int n, int x, int y, int N) {
    if (!isSafe(x, y, m, n)) // 境界を越えた場合
        return 0.0;
    if (N == 0) // N回の移動が完了した場合
        return 1.0;

    double probability = 0.0;
    probability += matProb(m, n, x - 1, y, N - 1) * 0.25; // 左へ移動
    probability += matProb(m, n, x, y + 1, N - 1) * 0.25; // 上へ移動
    probability += matProb(m, n, x + 1, y, N - 1) * 0.25; // 右へ移動
    probability += matProb(m, n, x, y - 1, N - 1) * 0.25; // 下へ移動
    return probability;
}

int main() {
    int m = 7, n = 8;
    int x = 1, y = 1;
    int N = 4;
    cout << "Matrix Probability is " << matProb(m, n, x, y, N);
}

実行結果

Matrix Probability is 0.664062

結果の解説

この例では、7×8 の行列の位置 (1, 1) から 4 回移動した場合を考えています。実行結果の 0.664062 は、4 回の移動を終えた時点で約 66.4% の確率で行列の内側に留まることを意味します。開始位置が端に近いほど境界の外に出やすいため、確率は低くなる傾向があります。

計算量

各移動ごとに4方向へ分岐するため、時間計算量は O(4N) となります。また、再帰の深さは最大 N であるため、空間計算量(再帰スタック)は O(N) です。N が大きくなると計算量が急増するため、動的計画法(メモ化)を組み合わせることで効率化することも可能です。

  1. C言語でスネークパターン(蛇行順)に行列を出力する方法

    n×nサイズの2次元配列が与えられたとき、要素の元の位置を一切変更せずに、スネークパターン(蛇行する順序)で配列の要素を出力するCプログラムを紹介します。例入力: arr[]= 100 99 98 97 93 94 95 96 92 91 90 89 85 86 87 88 出力: 100 99 98 97 96 95 94 93 92 91 90 89 88 87 86 85このプログラムでは、行列の各行を順番に走査し、その行が偶数行か奇数行かを判定することで処理を切り替えます。偶数行(0行目、2行目など)の場合:その行の要素を左から右へ出力します。奇数行(1行

  2. C++で解くチェス盤上のナイトが盤内に残る確率の求め方

    問題概要 N×Nのチェス盤があるとします。ナイトはr行c列目のマスからスタートし、ちょうどK回の移動を試みます。行と列は0始まりのインデックスで表されるため、左上のマスは(0, 0)、右下のマスは(N-1, N-1)となります。 ナイトは1つのマスから8種類の異なるマスへ移動することができます。その移動パターンは下図の通りです。 ナイトは移動のたびに、8つの可能な移動の中からランダムに1つを選択します。そして、ちょうどK回の移動を完了するか、チェス盤の外に出てしまうまで移動を続けます。この問題では、ナイトが移動を終えた時点で盤上に残っている確率を求めます。 例えば、入力が「3, 2, 0,