配点: 400 点 / 実行時間制限: 2 sec / メモリ制限: 1024 MB / Difficulty: 1048 / NoviSteps: 1Q
問題概要
頂点
辺の有向グラフがあり、辺
は頂点
から頂点
への重み
の有向辺である。
頂点 から頂点
への walk のうち、walk に含まれる辺の重みのビット単位
の最小値を求めよ。
制約
- 入力は全て整数。
考察
この問題が厄介なのは、グラフ上のサイクルを経由することで 和が変動してしまう点にある。つまり、「今どの頂点にいるか」だけでは経路の
和が一意に定まらないのである。
そこで、
- 状態
現在の頂点が
で、頂点
から
までの
和が
である
を新たな頂点としたグラフ を考える。
元の有向グラフ において、
の重みあり有向辺が張られているとき、
では全ての可能な
和
に対して
の重みなし有向辺が張られる。
したがって、求めるべきなのは、「 上で頂点
から到達可能な頂点
について、
が最小となるようなもの」である。
これは、 上で BFS / DFS を行うことで求めることができる。
ここで用いたのは「頂点倍加」というテクニックで、グラフの次元を上に伸ばすことで、同じ頂点にいても異なる状態を扱うことができるというイメージ。
実装例
#include <bits/stdc++.h> using namespace std; #define rep(i, start, end) for (auto i = (start); (i) < (end); (i)++) template <class T> using Graph = vector<vector<T>>; // ======================================== // struct Edge { int to; int weight; }; int main() { int N, M; cin >> N >> M; Graph<Edge> G(N); rep(i, 0, M) { int A, B, W; cin >> A >> B >> W; A--, B--; G[A].push_back({B, W}); } vector<vector<bool>> visited(N, vector<bool>((1 << 10), false)); queue<pair<int, int>> que; que.push({0, 0}); visited[0][0] = true; while (!que.empty()) { auto [now, sum] = que.front(); que.pop(); for (auto &&edge : G[now]) { int next_v = edge.to; int next_sum = sum ^ edge.weight; if (!visited[next_v][next_sum]) { visited[next_v][next_sum] = true; que.push({next_v, next_sum}); } } } rep(bit, 0, (1 << 10)) { if (visited[N - 1][bit]) { cout << bit << endl; return 0; } } cout << -1 << endl; return 0; }
実装時間: 40分
コメント
頂点倍加の問題はまだあまり馴染みがないので、いろいろ経験していきたいところ。
ところでこれが緑中位Diffってマジか...