[ABC244] G - Construct Good Path

[Q] https://atcoder.jp/contests/abc244/tasks/abc244_g

Fとほぼ同じような問題設定なので、FとGが同じURLでバグってるのかと思った。

問題文を読むと、
「S に関する長さ 4N 以下の良いパスが少なくとも 1 つ存在することが示せます。」
4Nと特殊な指定があるので、貪欲ルールを発見するんだろうと思う。

そして、グラフが木だとしたら、葉っぱから貪欲に確定できそう。

1 - 2 - 3 - 4
という木について。

自分が2にいる場合。
1を奇数回踏みたかったら、2,1,2とすればいいし、
1を偶数回踏みたかったら、2,1,2,1,2とすればいいし、2, だけで1を踏まなくてもいい。

2にいるときに1を確定させて、
3にいるときに2を確定させて、
4にいるときに3を確定させる。

これは、1頂点あたり4手で確定できそう。

ということで、
1. グラフは木を張る。
2. DFSする。いったん深く潜る。
3. DFSで、戻るときに、葉側にある頂点の状態を確定させる。

実装

queue<ll> ans;
ll N, M;
string S;

void dfs(ll u, ll p, bool hash[100010]) {
 // いったん深く潜る
 for (auto v : G[u]) {
   if (v == p) continue;
   ans.push(v);
   hash[v] ^= 1;
   dfs(v, u, hash);
 }
 // 戻る。
 if (p == -1) return;
 ans.push(p);
 hash[p] ^= 1;
 // u:pよりも葉に近い頂点。これが、Sと合致しないなら調整する。
 if ('0' + hash[u] != S[u]) {
   ans.push(u);
   ans.push(p);
   hash[u] ^= 1;
   hash[p] ^= 1;
 }
}

int main() {
 cincout();

 cin >> N >> M;
 // UnionFind
 G.assign(N + 1, vector<ll>());
 seen.assign(N + 1, false);
 UnionFind tree(N);
 rep(i, M) {
   ll u, v;
   cin >> u >> v;
   --u, --v;
   // 木を構成するN-1辺を採用する
   if (tree.issame(u, v)) continue;
   G[u].push_back(v);
   G[v].push_back(u);
   tree.unite(u, v);
 }
 cin >> S;

 bool hash[100010]{};
 hash[0] = true;
 ans.push(0);
 dfs(0, -1, hash);
 // スタート値0の偶奇が考慮できていないので処理。
 if ('0' + hash[0] != S[0]) {
   ans.pop();
 }
 cout << ans.size() << endl;
 while (!ans.empty()) {
   cout << ans.front() + 1;
   ans.pop();
   if (ans.empty())
     cout << endl;
   else
     cout << " ";
 }
}

https://atcoder.jp/contests/abc244/submissions/30302288


いいなと思ったら応援しよう!