公式
F - Exactly K Steps 2 解説 by en_translator
Let \(c ^ k _ {i,j}\) denote the total cost to travel from vertex \(i\) to vertex \(j\) via exactly \(k\) edges. Consider the sequence \(c ^ k=(c ^ k _ {i,j}) _ {1\le i\le N,1\le j\le N}\) indexed by \((i,j)\). We have \(c ^ 1=(C _ {i,j}) _ {1\le i\le N,1\le j\le N}\).
Given \(c ^ a\) and \(c ^ b\), the algorithm yields \(c ^ {a+b}\):
- Initialize \(x _ {i,j}\leftarrow\infty\).
- For all \((i,j,k)\in\lbrace1,2,\ldots,N\rbrace ^ 3\), repeat the following:
- Set \(x _ {i,k}\leftarrow\min\lbrace x _ {i,k},c ^ a _ {i,j}+c ^ b _ {j,k}\rbrace\).
- \(x\) is the sought \(c ^ {a+b}\).
This can be interpreted as a matrix product on the min-plus semiring.
This algorithm enables to find the answer using fast exponentiation in \(O(N ^ 3\log K)\) time.
The following is sample code:
#include <iostream>
#include <vector>
#include <ranges>
#include <algorithm>
int main() {
using namespace std;
unsigned N, K;
cin >> N >> K;
vector C(N, vector<unsigned long>(N));
for (auto&& row : C)
for (auto&& c : row)
cin >> c;
// Finds results of (a + b) moves, given results of a moves and b moves
const auto prod{[N, inf{ranges::max(C | views::join) * K}](const auto& lhs, const auto& rhs) {
// Initialize with a sufficiently large value
vector ret(N, vector(N, inf));
for (const auto i : views::iota(0U, N))
for (const auto j : views::iota(0U, N))
for (const auto k : views::iota(0U, N))
ret[i][k] = min(ret[i][k], lhs[i][j] + rhs[j][k]);
return ret;
}};
auto ans(C);
--K;
// Fast exponentiation
while (K) {
if (K & 1)
ans = prod(ans, C);
C = prod(C, C);
K /= 2;
}
for (const auto i : views::iota(0U, N))
cout << ans[i][i] << endl;
return 0;
}
投稿日時:
最終更新: