回答:
時間で機能する非常に実用的なアプローチが存在します。ここで、はプロセッサワードのビット数です。主な考え方は、マトリックスの要素を1つずつ昇順で繰り返し(任意にタイを解除)、「スイッチをオンにする」というものです。いくつかのトリプルの最大要素がオンになった瞬間を考えてみます。簡単にするために、上記の要素がであると仮定しましょう。最後の要素がオンになったときに、トリプルの値を答えに追加するのは自然なことです。したがって、とような可能なの数を数える必要がありますすでにオンになっています(これはトリプルの数になります。ここではが最大の要素なので、今は完全にオンになっています)。ここでは、ビット最適化を使用することにより、単純な実装を高速化できます。
詳細については、で機能するC ++ 11の次の実装を参照してください (これはあまり最適化されていません。ただし、少なくとも私のマシンでは、単純な合計を大幅に上回っています)。
// code is not very elegant,
// but should be understandable
// here the matrix a has dimensions n x n
// a has to be symmetric!
int64_t solve (int n, const vector<vector<int32_t>> &a)
{
std::vector<boost::dynamic_bitset<int64_t>> mat
(n, boost::dynamic_bitset<int64_t>(n));
vector<pair<int, int>> order;
for (int j = 1; j < n; j++)
for (int i = 0; i < j; i++)
order.emplace_back(i, j);
sort(order.begin(), order.end(),
[&] (const pair<int, int> &l, const pair<int, int> &r)
{return a[l.first][l.second] < a[r.first][r.second];});
int64_t ans = 0;
for (const auto &position : order)
{
int i, j;
tie (i, j) = position;
mat[i][j] = mat[j][i] = 1;
// here it is important that conditions
// mat[i][i] = 0 and mat[j][j] = 0 always hold
ans += (mat[i] & mat[j]).count() * int64_t(a[i][j]);
}
return ans;
}
あなたが浮気ビットの最適化を使用することを検討している場合は、得、ここで同じ結果に4つのロシアの方法を使用することができますあまり実用的でなければならないアルゴリズム、(ので最も近代的なハードウェア上でかなり大きいです)しかし理論的にはより優れています。実際、を選択し、行列の各行を整数の配列としてからまで保持します。ここで、番目の数は配列は、から行のビットに対応し-インデックス。時間でそのような2つのブロックごとのスカラー積を事前計算できます。整数を1つだけ変更しているため、行列内の位置の更新は高速です。行とのスカラー積を見つけるには、その行に対応する配列を反復処理するために、対応するブロックのスカラー積をテーブルで検索し、得られた積を合計します。
上記の段落では、整数操作に時間かかると仮定しています。アルゴリズムの比較速度を実際には変更しないため、これは非常に一般的な仮定です(たとえば、この仮定を使用しない場合、ブルートフォースメソッドは実際には 時間で機能します(ここではビット演算で時間を測定します)が一定ので少なくともまでの絶対値を持つ整数値を取る 場合(それ以外の場合は、とにかく行列乗算)が4つのロシア方法が使用上記で示唆その場合、サイズ数の操作。そのため、ビット演算が行われますが、モデルの変更にもかかわらず、ブルートフォースよりも優れています)。
、アプローチの存在についての質問はまだ興味深いものです。
この回答で示されている手法(ビット最適化と4つのロシア語の手法)は決して独創的なものではなく、説明を完全にするためにここに示しています。しかし、それらを適用する方法を見つけることは簡単ではありませんでした。
mat[i]
mat[j]
mat
どちらが重要と思われるかを定義していません。どのように定義できるかは理解して(mat[i] & mat[j]).count()
いますが、どのSTLコンテナでも希望どおりに機能するかどうかは疑問です。
mat
-私は使用する必要があると思いますstd::vector<boost::dynamic_bitset<int64_t>>
。
mat
:はい、実際には標準のビットセットを念頭に置いていましたboost::dynamic_bitset
が、サイズがコンパイル時の定数である必要がないため、この場合はさらに優れています。答えを編集して、この詳細を追加し、4つのロシア語のアプローチを明確にします。