ARC224 C - Ascending Labels
昇順ラベル
考え方
小さい数が大量にあると、隣接の中に $1$ 小さい値が複数あって条件に反する危険が大きい。
ということで、頂点 $1$ の値を $0$ に決めた後で、以下をループして貪欲に埋めていけばよい。
- まだ数を決めていない頂点の中で、隣接頂点に書かれている数の最大値が最も大きいものを選ぶ
- その最大値に $1$ を加えた数を、その頂点の値に決める
さて、これで、どの頂点も隣接に自身より $1$ 小さい値が少なくとも $1$ つ存在することは保証される。
あとは、それが $2$ つ以上になることがないことを示せばよい。
仮に、頂点 $X$ の隣接である $Y,Z$ が $1$ 小さい値をもつという状態が発生したとしよう。
この $3$ つの中で、最後に追加したのが $X$ であることはありえない。
なぜなら、$Y$ と $Z$ の片方が決まった段階で $X$ が選択肢に入ってくるから。
$X$ を $Y$ の値より $1$ 大きい値に決める選択肢にあるのに、先に $Z$ が $Y$ と同じ値に決まることはない。
しかし、最後に追加したのが $Y$ であることもありえない。
なぜなら、$Y$ は $X$ に隣接しているので、$Y$ が $X$ より $1$ 小さい値に決まることはありえない。
$Z$ についても同様。
したがって、そのような状態が発生すると、決定順位に必ず矛盾が発生する。
すなわち、そのような状況は絶対に発生しない。
ということで、冒頭に述べた貪欲法で構成していけばよい。
そして、実のところ、これはただの深さ優先探索であり、計算量は $O\left(\sum (N+M)\right)$ である。
入力例1での動作
$1$ つ目のテストケースのみ考える。
入力を受け取る。
n: 6
m: 7
edges:
(1, 5)
(1, 3)
(3, 5)
(2, 5)
(3, 4)
(3, 6)
(4, 6)
頂点 $1$ を根として、入力順の隣接リストで深さ優先探索する。
最初に頂点 $1$ の値を $0$ とする。
頂点 $1$ から頂点 $5$ へ進むので、頂点 $5$ の値を $1$ とする。
頂点 $5$ から未訪問の頂点 $3$ へ進み、値を $2$ とする。
頂点 $3$ から頂点 $4$ へ進み、値を $3$ とする。
頂点 $4$ から頂点 $6$ へ進み、値を $4$ とする。
頂点 $6$ から先には未訪問の頂点がないので戻る。
その後、頂点 $5$ から未訪問の頂点 $2$ へ進み、値を $2$ とする。
したがって、各頂点の値は次のようになる。
a: {0, 2, 2, 3, 1, 4}
例えば頂点 $3$ の値は $2$ である。
隣接する頂点 $1,5,4,6$ の値はそれぞれ $0,1,3,4$ なので、値が $1$ 小さい頂点は頂点 $5$ だけである。
他の頂点についても同様に条件を満たすため、この列を出力できる。
注意点
再帰による深さ優先探索では、言語によっては再帰が深くなりすぎてエラーする場合がある。
その場合は、stack を用いる方の実装にする必要がある。
C++では、この程度では何も問題ないようである。
別解
特になし。