0

プロジェクト オイラー問題 11のソリューション コードでは、次の関数を取得しました。問題 8から一般化された、連続した ed 数Max_consecutive_prodの最大積を計算するクラスです。6 つの関数は、さまざまな方向のさまざまなシリーズで最大製品を計算し、グリッドのさまざまなエッジから開始します。input()

これらの関数の唯一の違いは、forステートメントのインデックスです。明らかな重複を排除するにはどうすればよいですか? ここでの状況は、典型的なtemplate methodパターンの適用とは逆です。操作は同じですが、制御フレームワークが異なります。これに対する別の設計パターンはありますか?

編集:コメントで指定されたすべての変更は(2つの)forステートメントに対するものであり、各関数のループ本体は最初のものと同じです。

template <size_t size> unsigned process_row(const unsigned (&grid)[size][size])
{
    unsigned prodMax = 0;
    for (int i = 0; i < size; ++i)
    {
        Max_consecutive_prod mcp;
        for (int j = 0; j < size; ++j)
        {
            mcp.input(grid[i][j]);
        }
        if (mcp.result() > prodMax)
        {
            prodMax = mcp.result();
        }
    }
    return prodMax;
}
// exchange i, j in process_row
template <size_t size> unsigned process_col(const unsigned (&grid)[size][size])
{
    // ...
}

template <size_t size> unsigned process_diag_lower(const unsigned (&grid)[size][size])
{
    unsigned prodMax = 0;
    for (int init = 0; init < size; ++init)
    {
        Max_consecutive_prod mcp;
        for (int i = init, j = 0; i < size && j < size; ++i, ++j)
            // ...
        // ...
    }
    return prodMax;
}
// exchange i, j in process_diag_lower
template <size_t size> unsigned process_diag_upper(const unsigned (&grid)[size][size])
{
    // ...
}
// flip j in process_diag_lower
template <size_t size> unsigned process_rev_diag_lower(const unsigned (&grid)[size][size])
{
    unsigned prodMax = 0;
    for (int init = 0; init < size; ++init)
    {
        Max_consecutive_prod mcp;
        for (int i = init, j = size-1; i < size && j >= 0; ++i, --j)
            // ...
        // ...
    }
    return prodMax;
}
// change ++j in process_diag_upper to --j
template <size_t size> unsigned process_rev_diag_upper(const unsigned (&grid)[size][size])
{
    unsigned prodMax = 0;
    for (int init = 0; init < size; ++init)
    {
        Max_consecutive_prod mcp;
        for (int j = init, i = 0; j >=0 && i < size; ++i, --j)
            // ...
        // ...
    }
    return prodMax;
}

6 つの関数の制御フローにおける実際の共通性と可変性を示すランダムハッカーのコードに基づいて、私は自分のバージョンを書き、コードをより自己説明的で C++ の慣用句にしました。stragegyクラスを使用し、ローカル変数を定義してコードを明確にし、効率を改善します。の非テンプレート バージョンを定義して、process()異なるものをインスタンス化するときにバイナリ コードが肥大化するのを回避しますsize(「効果的な C++」、項目 44 を参照)。

それでも混乱する場合は、random-hacker's answer の説明をお読みください。:)

namespace Grid_search
{
    enum Step { neg = -1, nul, pos };
    enum Index_t { i, j };

    struct Strategy
    {
        Step direction[2];
        Index_t varOuter;
    };

    const size_t typeCount = 6;
    const Strategy strategy[typeCount] = { {{pos, nul}, i}, {{nul, pos}, j}, {{pos, pos}, i}, {{pos, pos}, j}, {{pos, neg}, i}, {{pos, neg}, j} };
};

template <size_t size> inline unsigned process(const Grid_search::Strategy& strategy, const unsigned (&grid)[size][size])
{
    return process(strategy, reinterpret_cast<const unsigned*>(&grid), size);
}

unsigned process(const Grid_search::Strategy& strategy, const unsigned* grid, size_t size)
{
    using namespace Grid_search;

    const Index_t varOuter = strategy.varOuter, varInner = static_cast<Index_t>(!varOuter);
    const Step di = strategy.direction[i], dj = strategy.direction[j];
    const unsigned initInner = strategy.direction[varInner] == pos ? 0 : size -1;

    unsigned prodMax = 0;
    unsigned index[2];
    unsigned &indexI = index[i], &indexJ = index[j];
    for (unsigned initOuter = 0; initOuter < size; ++initOuter)
    {
        Max_consecutive_prod mcp;
        for (index[varOuter] = initOuter, index[varInner] = initInner;
            0 <= indexI && indexI < size && 0 <= indexJ && indexJ < size;
            indexI += di, indexJ += dj)
        {
            mcp.input(grid[indexI*size + indexJ]);
            if (mcp.result() > prodMax)
            {
                prodMax = mcp.result();
            }
        }
    }
    return prodMax;
}


int main()
{
    static const size_t N = 20;
    unsigned grid[N][N];

    std::ifstream input("d:/pro11.txt");
    for (int count = 0; input >> grid[count/N][count%N]; ++count)
    {
    }

    unsigned prodMax = 0;
    for (int i = 0; i < Grid_search::typeCount; ++i)
    {
        unsigned prod = process(Grid_search::strategy[i], grid);
        if (prod > prodMax)
        {
            prodMax = prod;
        }
    }
}
4

5 に答える 5

0

グリッドを平らにして、左から右、上から下に 400 個の数字が一列に並んでいるとします。一番上の行は、最初の 20 個の数値 (つまり、インデックス 0、...、19) で構成されます。次の 20 個の数字の 2 番目の rwo など。一般に、行i(0 から始まる) は indexs に対応しますi*20, i*20 + 1, i*20 + 2, ..., i*20 + 19

では、列はどうでしょうか。一番上の行と同じように、一番左の列は位置 0 から始まります。それは位置 20 の次の要素 (2 行目の最初の要素)、次に 40jですj, j + 20, j + 40, ..., j + 19*20

対角線はそれほど違いはありません。紙に書いてみてください(方眼紙はこの種のものに適しています.

もう 1 つのヒント: 同じ 4 つの要素を右から左に乗算するよりも、左から右に乗算する 4 つの要素の積を見つけた場合、違いはありますか?

于 2013-10-30T03:14:50.567 に答える
0

Adam Burry と Tony D によって提案されているように、内側のループ コード ブロックを通常の関数に貼り付けた後、既に持っているものは問題ないと思いますが、必要に応じてループを結合し、テーブルを使用して移動可能な方向をエンコードできます。秘訣は、別のandp[2]の代わりに配列を使用して、テーブルによって駆動される外側のループでどのインデックスが変更されるかという問題を有効にすることです。次に、唯一のトリッキーなことは、内側のループで変化する他のインデックスが、各ステップで減少する場合、最大値 (0 ではなく) から開始する必要があることを確認することです。ij

enum indices { I, J };       // Can just use 0 and 1 if you want
template <size_t size> unsigned process(const unsigned (&grid)[size][size]) {
    static int d[][2] = { {1, 0}, {0, 1}, {1, 1}, {1, -1}, {1, 1}, {1, -1} };
    static int w[]    = {      J,      I,      J,       J,      I,       I };
    unsigned prodMax = 0;    // Note: not 1
    for (int k = 0; k < sizeof d / sizeof d[0]; ++k) {  // For each direction
        for (int init = 0; init < size; ++init) {
            Max_consecutive_prod mcp;
            int p[2];        // p[I] is like i, p[J] is like j
            for (p[w[k]] = init, p[!w[k]] = (d[k][!w[k]] == -1 ? size - 1 : 0);
                 min(p[I], p[J]) >= 0 && max(p[I], p[J]) < size;
                 p[I] += d[k][I], p[J] += d[k][J])
            {
                mcp.input(grid[p[I]][p[J]]);
                prodMax = max(prodMax, mcp.result());
            }
        }
    }

    return prodMax;
}
于 2013-10-30T04:58:31.677 に答える
0

さまざまな状態の列挙型を作成し、それを関数に渡すことができます。次に、渡された値に基づいて値を設定する if ステートメントを作成します。

于 2013-10-30T01:52:22.617 に答える