配点: 400 点 / 実行時間制限: 2 sec / メモリ制限: 1024 MB / Difficulty: 601
問題概要
頂点に から
の、辺に
から
の番号がついた
頂点
辺の単純連結無向グラフが与えられる。辺
は頂点
と頂点
を結んでおり、ラベル
が付けられている。
頂点 から頂点
への単純パスのうち、パスに含まれる辺につけられたラベルの総 XOR としてあり得る最小値を求めよ。
制約
- 入力は全て整数。
考察
まず、 の制約が非常に小さいことに注目しよう。
グラフ上の辺数が最も大きくなるのは、与えられたグラフが完全グラフになるときで、このときの辺数は である。
理由(クリックで展開)
完全グラフとは「どの2点の間にも辺があるような単純グラフ」のことであるが、これは言い換えれば「自身以外の 個の頂点すべてと辺で接続している」ということになる。
したがって、1つの頂点からは 個の辺が出ていることになり、無向辺による重複を考慮すると、
頂点の完全グラフの辺数は
本となる。
このとき、任意の頂点から他の頂点へ行くことが可能になる。
- 頂点
から、頂点
以外の頂点(頂点
とする)への行き方は
通り。
- 頂点
から、頂点
以外の頂点(頂点
とする)への行き方は
通り。
... という風に考えると、頂点 から頂点
までの単純パスは
通りであり、最大でも
通り。これなら十分に全探索が可能である。
単純パスの列挙には DFS を用いるのが良いだろう。訪問済みの頂点までのパスの総 XOR を持ちながら再帰していくとラク。
注意点としては、ラベルの最大値が であること。仮の答えの初期値を
とかにしておくとバグってしまう。
実装例
#include <bits/stdc++.h> using namespace std; #define rep(i, start, end) for (auto i = (start); (i) < (end); (i)++) template <typename T> inline bool chmin(T &a, T b) { return ((a > b) ? (a = b, true) : (false)); } // ======================================== // using ull = unsigned long long; constexpr ull MAX = ULLONG_MAX; struct Edge { int to; ull cost; }; int main() { int N, M; cin >> N >> M; Graph<Edge> G(N); rep(i, 0, M) { int u, v; ull w; cin >> u >> v >> w; u--, v--; G[u].push_back({v, w}); G[v].push_back({u, w}); } vector<bool> visited(N, false); ull ans = MAX; visited[0] = true; auto dfs = [&](auto self, int now, ull cost) -> void { if (now == N - 1) { chmin(ans, cost); return; } for (auto &&next : G[now]) { if (visited[next.to]) continue; visited[next.to] = true; self(self, next.to, cost ^ next.cost); visited[next.to] = false; } }; dfs(dfs, 0, 0); cout << ans << endl; return 0; }
実装時間: 35分
コメント
DFS の実装には、最近覚えたラムダ式を使ってみた。クセはあるが、外部変数の参照が簡単に行えるので結構オススメ。