4

次のような正の値のみを持つn:nマトリックスがあるとします。short

0 1 0 3
1 0 5 6
7 1 0 4
6 2 7 9

m:mこの行列内で、0 より大きい値を最も多く含む行列を探しています。私の問題は、これまでの解決策がn(nor m) でうまくスケーリングされないことです。

実際、n:nマトリックスは製品の価格を表し、軸は特定の (任意の) 日からの日数を表しています。そのため、特定の時間間隔で価格を検索できます。マトリックスは実際にはm:m、価格のサブセット (ビューなど) を含む 7 x 7 マトリックスです。n:n最も多くの価格が記入されているマトリックスの部分を探しています。

上記の例では、m:mマトリックスは

7 1
6 2

2 はどこmですか。

これまでに作成したプロトタイプの関連部分は次のとおりです。

private static class ResultMatrixData {
    private byte fillCount;
    private short distanceFromToday;

    public ResultMatrixData() {
        fillCount = 0;
        distanceFromToday = Short.MAX_VALUE;
    }

    public ResultMatrixData(short[][] pricesMatrix, short iArg, short jArg) {
        byte fillCount = 0;
        for (int i = iArg; i < iArg + 7; i++) {
            for (int j = jArg; j < jArg + 7; j++) {
                if (pricesMatrix[i][j] > 0) {
                    fillCount++;
                }
            }
        }
        this.fillCount = fillCount;
        distanceFromToday = iArg > jArg ? iArg : jArg;
    }
}

private ResultMatrixData calculateSingleResult(short[][] pricesMatrix) {
    ResultMatrixData bestSoFar = new ResultMatrixData();
    ResultMatrixDataComparator comparator = new ResultMatrixDataComparator();
    for (short i = 0; i < NUMBER_OF_DAYS - 6; i++) {
        for (short j = 0; j < NUMBER_OF_DAYS - 6; j++) {
            ResultMatrixData current = new ResultMatrixData(pricesMatrix, i, j);
            if (comparator.compare(current, bestSoFar) >= ResultMatrixDataComparator.GREATER_THAN) {
                bestSoFar = current;
            }
        }
    }
    return bestSoFar;
}

private static class ResultMatrixDataComparator implements Comparator<ResultMatrixData> {
    private static final int LESS_THAN = -1;
    private static final int EQUAL = 0;
    private static final int GREATER_THAN = 1;

    @Override
    public int compare(ResultMatrixData first, ResultMatrixData second) {
        if (first.fillCount > second.fillCount) {
            return GREATER_THAN;
        } else if (first.fillCount < second.fillCount) {
            return LESS_THAN;
        } else {
            if (first.distanceFromToday < second.distanceFromToday) {
                return GREATER_THAN;
            } else if (first.distanceFromToday > second.distanceFromToday) {
                return LESS_THAN;
            }
        }
        return EQUAL;
    }
}

私の問題は、実行時間が二次または指数関数的に見えることです(正確な漸近分析を実行しませんでした):

n (days)  | running time in ms 
1 *  365  | 48
2 *  365  | 123
3 *  365  | 278
4 *  365  | 482
5 *  365  | 733
6 *  365  | 1069
7 *  365  | 1438
8 *  365  | 1890
9 *  365  | 2383
10 * 365  | 2926
11 * 365  | 3646
12 * 365  | 4208
13 * 365  | 5009

このアルゴリズムを最適化する方法について何か提案はありますか?

注: これは宿題の演習ではありません。

編集:他の人が答えで言ったように、ここでの時間の複雑さは約O((n- m)^ 2)です。nサブ二次であり、無限に収束しながらうまくスケーリングするものを探しています。

4

4 に答える 4

0

このようなアプローチでどこまで行けるかはまったくわかりませんが、ここでは
行と列を入れ替えて、ゼロを左上から遠ざけるようにします。
したがって、結果の行列 m:m は左上に表示されます。

行/列を交換することが興味深いかどうかを評価する必要があります。
このために、この重みのマトリックスに基づいてコスト関数を構築します。

 7 6 5 4 3 2 1
 6 6 5 4 3 2 1
 5 5 5 4 3 2 1
 4 4 4 4 3 2 1
 3 3 3 3 3 2 1
 2 2 2 2 2 2 1
 1 1 1 1 1 1 1

つまり、行 i、列 j (0 ベース) の重みは min(ni,nj) です。

検出された 0 ごとに対応する重みのコストがかかるため、総コストを最小限に抑えたいと考えています。
総コストが削減される場合、スワップは興味深いものです。

評価コストを削減するために、疎行列に一種の構造を使用できます。

  • 行ごとにゼロ位置をマップします。これは、各行インデックスの (columnIndex) のコレクションです。
  • 列ごとにゼロ位置をマップします。これは、各 columnIndex の (rowIndex) のコレクションです。

行と列の並べ替えの問題が発生しました。
次善のアプローチは、部分問題を個別に解決することから成ります。

  • 行を交換し、
  • 列を交換し、
  • コストが変化しなくなるまで繰り返します。

次の場合、2 つの行 i と k を交換する利点があります。

weigth.atRow(i).sumOfIndices(zerosPerRow.at(i)) + weigth.atRow(k).sumOfIndices(zerosPerRow.at(k)) >
weigth.atRow(i).sumOfIndices(zerosPerRow.at(k)) + weigth.atRow(k).sumOfIndices(zerosPerRow.at(i))

これは完全な順序関係ではないため、すべてのソート アルゴリズムが成功するわけではないことに注意してください。

おそらく、ヒューリスティックを追加して組み合わせをさらに削減することに関心があるかもしれません。最もゼロの多い行を一番下にスワップし、最もゼロの多い列を右にスワップします。

明らかに、完全なランクの行/列は、一度上/左に移動するとソートする必要はありません。

したがって、おそらく、同じランクの行/列のサブセットをソートすることは、合理的に (準) 最適なアルゴリズムです。

于 2013-07-16T22:15:37.153 に答える