中国人郵便配達問題
概要
中国人郵便配達問題を動的計画法によって解きます.考察すると奇数次頂点の最小マッチングになります.
計算量
$O(V^2 2^V)$
実装
int chinesePostman(const Graph &g) {
static const Weight INF = std::numeric_limits<Weight>::max() / 8;
Weight total = 0;
int n = g.size();
std::vector<int> odds;
static Weight dist[17][17];
for (int i = 0; i < n; ++i) {
std::fill(dist[i], dist[i] + n, INF);
for (auto &e : g[i]) {
int s = e.src, d = e.dst;
Weight w = e.weight;
total += w;
dist[s][d] = std::min(dist[s][d], w);
}
if (g[i].size() & 1) odds.push_back(i);
}
for (int k = 0; k < n; ++k)
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j) dist[i][j] = std::min(dist[i][j], dist[i][k] + dist[k][j]);
static Weight dp[1 << 17];
int k = odds.size();
std::fill(dp, dp + (1 << k), INF);
dp[0] = 0;
for (int S = 0; S < 1 << k; ++S)
for (int i = 0; i < k; ++i)
if (~S >> i & 1)
for (int j = 0; j < i; j++)
if (~S >> j & 1)
dp[S | 1 << i | 1 << j] =
std::min(dp[S | 1 << i | 1 << j], dp[S] + dist[odds[i]][odds[j]]);
return total / 2 + dp[(1 << k) - 1];
}