ですから、これは私の宿題ではありませんが、アルゴリズムとデータ構造(これで完了です)に関するコースのコースの評定されていない宿題から取ったものです。
N行n列のグリッドが表示されます。隣接するすべての値よりも小さい数は、極小値です。 (数値の近傍は、すぐ上、下、左、または右の1つです。ほとんどの数値には4つの近傍があります。側面の数値には3つあります。4つの角には2つあります。)分割統治アルゴリズム設計を使用します。数値のペア間のO(n)比較のみで極小値を計算するためのパラダイム。 (注:n2 入力の数値は、それらすべてを見る余裕はありません。ヒント:どのタイプの再発が望ましい上限を与えるかを考えてください。)
番号は順不同なので、O(n以外のことをどのようにして回避できるかわかりません。2)比較。
ジャレッドの答えのように、それがどのようにうまくいかないかを見ることで、言葉を適応させることができます。
その答えのアイデア-これは良いことです-は「下り坂を転がる」ことです。これは、要素を使用している場合、それが極小値であるかどうかを確認することを意味します。その場合は、完了です。それ以外の場合は、最近傍の最小値に進みます。最終的にこれは終了する必要があります。これは、すべてのステップがより小さな要素に対するものであり、有限配列では永遠に続くことができないためです。
このアプローチの問題は、「ローリング」がいたるところに蛇行する可能性があることです。
20 100 12 11 10 100 2
19 100 13 100 9 100 3
18 100 14 100 8 100 4
17 16 15 100 7 6 5
左上から「下り坂」を開始すると、配列内の要素の約半分にアクセスします。それは多すぎるので、少し制限する必要があります。
中央の列と中央の行を調べることから始めます。それらすべての中で最小の要素を見つけて、そこから始めます。
そこから1歩「下り坂」を転がり、4つの象限の1つに入ります。中央の列または行、あるいはその両方の隣接要素が大きいため、象限の1つを入力します。したがって、隣接する2つの象限のうちの1つだけが "下り坂"になります。
ここから「下り坂」を走ったらどうなるかを考えてみましょう。明らかに、最終的には極小値に達します。 (時間がかかりすぎるので、実際にはこれを行いません。)しかし、動き回る過程で、その象限を離れることは決してありません。 。そうするためには、中央の列または中央の行のいずれかを横切る必要があり、これらの要素はどれも最初の場所よりも小さくありません。したがって、その象限には極小値が含まれています。
したがって、線形時間で、極小値を含む必要がある象限を特定し、nを半分に削減しました。今すぐ再帰します。
このアルゴリズムには2n + 2n/2 + 2n/4 + ...の時間がかかります。これは4nに等しく、O(n)なので、これで完了です。
興味深いことに、重要な部分を除いて、「ローリングダウンヒル」をほとんど使用しませんでした。アルゴリズムが機能することを証明します。
[更新]
Incassatorが指摘 のように、この答えは完全に正しくはありません。「再帰した」後、象限から再びロールアウトする可能性があるためです...
最も簡単な修正は、「下り坂を転がる」前に、中央の行、中央の列および境界の中で最小の要素を見つけることです。
Nemoが承認した答えはいいですが、完全には正しくありません。
したがって、線形時間で、極小値を含む必要がある象限を特定し、nを半分に削減しました。今すぐ再帰します。
私は「ただの再帰」ビットについて言及しています。問題は、次の反復でnot元のグリッドの極小値(次のxは任意の大きな数を意味する)である極小値を見つける可能性があるため、直接実行できないためです。
x x 39 x x 50 x x x x x
x x 38 x x 49 x x x x x
37 36 33 34 35 48 x x x x x
x x 32 x 1 10 x x x x x
x x 31 x x 47 x x x x x
46 45 30 44 43 60 51 52 53 54 55
x x 2 x x 56 x x x x x
x x x x x 57 x x x x x
x x x x x 58 x x x x x
x x x x x 59 x x x x x
最初の反復では、10が中央の行と中央の列の最小値であることがわかります。左に移動します(1は10未満なので)。したがって、次の反復は左上の象限です。しかし、現在、中央の行と列の最小値は31(象限の境界がその一部と見なされる場合は30)になります。次に、それは極小値であると結論付けます。しかし、それは完全なグリッドのためではありません。
この不幸な欠陥はさまざまな方法で修正できます。私はそれを次のように解決しました:
グリッド自体に加えて各反復で、現在の最小候補を追跡します(最初の反復後の上記の例では1です。初期状態では、最小候補はプラス無限大と言えます)。中央の行と列の最小値を計算し、最小候補と比較します。後者が小さい場合は、象限最小候補を含むに再帰します。そうでない場合は、前の候補を忘れてから、新しい中央の行/列の最小値が実際に局所的な最小値であるかどうかを確認します。そして、そうでない場合は、通常のように再帰して、そこから下降する象限に移動します(そして新しい最小候補を追跡します)。
または、 これはおそらくMIT講義 で説明されているように手順を変更できます:各行で、中央の行/列ではなく中央の行/列を見ることができますandグリッド境界次に、アルゴリズムが再び正しくなります。
あなたはあなたが好きな方法を選択します。
これは本当に簡単だと思います。
問題を3Dに変換して、アルゴリズムが機能する理由を確認します。マトリックスをテーブルに置きます。各セルから伸びている柱があり、柱の高さがその値に正比例しているとしましょう。任意の柱にボールを置きます。極小になるまで、ボールが常に最も低い高度である隣接する柱に落ちるようにします。
まあ、これはあなたがそれを分割して征服する方法です。
1)n x n行列を4つのn/2 x n/2サブ行列に分割します。
2)2 x 2マトリックスになるまで、サブマトリックスを再帰的に分割し続けます
3)2 x 2行列の要素が局所的な最小値かどうかを確認します。
漸化式は次のとおりです:T(n)= 4 * T(n/2)+ O(1)
4 * T(n/2)は4 n/2 x n/2サブ行列、O(1) 2 x 2サブ行列に極小があるかどうかをチェックするため
マスター定理は、これはO(n ^ 2)最悪の場合の限界であると述べています。
しかし、私は最良のケースO(n)バウンドを取得できると思います、
( "RED ALERT!--- BEST CASE IS BOGUS、JUST BOGUS --- RED ALERT!")。
手順3で極小値を見つけた後に再帰スタックを終了した場合。
疑似コード:
private void FindlocalMin(matrix,rowIndex,colIndex,width){
if(width == 1){ checkForLocalMinimum(matrix,rowIndex,colIndex); return;} //2x2 matrix
FindlocalMin(matrix,rowIndex,colIndex,width/2);
FindlocalMin(matrix, (rowIndex + (width/2) + 1) ,colIndex,width/2);
FindlocalMin(matrix,rowIndex, (colIndex + (width/2) + 1) ,width/2);
FindlocalMin(matrix,(rowIndex + (width/2) + 1), (colIndex + (width/2) + 1) ,width/2);
}
private void checkForLocalMinimum(.........){
if(found Local Minimum in 2x2 matrix){ exit recursion stack;}
}
これが Java実装 です。
Algorithms 4th Edition Book Exerciseの演習に従って開発された、3 * 3以上のマトリックス用のコード機能。
それは次のように機能します
パブリッククラスMinimumOfMatrix {
private static int findLocalMinimum(int[][] matrix, int rowStart, int rowEnd, int colStart, int colEnd) {
int midRow = (rowStart + rowEnd) / 2;
int minPos = findMin(matrix, midRow, colStart, colEnd);
if (minPos >= (colStart + colEnd) / 2)
colStart = (colStart + colEnd) / 2;
else
colEnd = (colStart + colEnd) / 2;
if (matrix[midRow][minPos] < matrix[midRow + 1][minPos]
&& matrix[midRow][minPos] < matrix[midRow - 1][minPos]) {
return matrix[midRow][minPos];
} else if (matrix[midRow][minPos] > matrix[midRow + 1][minPos]) {
return findLocalMinimum(matrix, midRow, rowEnd, colStart, colEnd);
} else {
return findLocalMinimum(matrix, rowStart, midRow, colStart, colEnd);
}
}
private static int findMin(int[][] matrix, int midRow, int colStart, int colEnd) {
int min = Integer.MAX_VALUE;
int pos = -1;
for (int i = colStart; i < colEnd; i++) {
if (matrix[midRow][i] < min) {
min = matrix[midRow][i];
pos = i;
}
}
return pos;
}
public static void main(String[] args) {
// Best Case
/*
* int[][] matrix= { {1,-2,4,-6,1,8}, {-3,-6,-8,8,1,3}, {1,2,6,-2,-8,-6},
* {-2,9,6,3,0,9}, {9,-1,-7,1,2,-6}, {-9,0,8,7,-6,9} };
*/
// Two Iteration Down Case
/*
* int[][] matrix= { { 1,-2, 4,-6, 1, 8}, {-3,-6,-8, 8, 1, 3}, { 1, 2, 6, 9, 0,
* 6}, {-2, 9, 6,-1,-1, 9}, { 9,-1,-7, 1, 2,-6}, {-9, 0, 8, 7,-6, 9} };
*/
/*
* //Left Down Case int[][] matrix= { { 1,-2, 4,-6, 0, 8}, {-3,-6,-8, 8,-2, 3},
* {-2, 9, 6,-1, 1, 9}, { 1, 0, 6, 9, 2, 6}, { 9,-1,-7, 1, 2,-6}, {-9, 0, 8,
* 7,-6, 9} };
*/
int[][] matrix = { { 1, -2, 4, }, { -3, -6, -8, }, { -2, 9, 6, }
};
System.out.println(findLocalMinimum(matrix, 0, matrix.length, 0, matrix.length));
}
}