プロジェクト オイラー問題 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;
}
}
}