ログインしてください。
公式
C - Lining Up 2 解説
by
C - Lining Up 2 解説
by
MMNMM
次のような数列 \((B _ i) _ {1\leq i\leq N}\) を考えます。
\[B _ i=\left\lbrace\begin{matrix}j&(A _ j=i)\hphantom{\text{otherwise}}\\-1&(\text{otherwise})\hphantom{A _ j=i}\end{matrix}\right.\]
これは、「人 \(i\) の直後の人は人 \(B _ i\)(ただし、存在しなければ \(-1\))」を満たす数列です。
この \((B _ i) _ {1\leq i\leq N}\) が求められれば、\(A _ x=-1\) を満たす \(x\) を用いて、列の並びを人 \(x,\) 人 \(B _ x,\) 人 \(B _ {B _ x},\) 人 \(B _ {B _ {B _ x}},\ldots,\) 人 \(B _ {B _ {{}_{\ddots _ {B _ x}}}}\) と書くことができます。
よって、数列 \((B _ i)\) と先頭の人を求めて \(x\leftarrow B _ x\) を適切に繰り返せばよいです。
実装例は以下のようになります。 直後の人が存在しないときの \(B _ i\) の値は(存在するときの値とかぶらない範囲で)自由に定めてよいことを利用しています。
#include <iostream>
#include <vector>
int main() {
using namespace std;
unsigned N;
cin >> N;
vector<unsigned> B(N, N); // B[i] := 人 i の直後の人(いなければ N)
unsigned front;
for(unsigned i = 0; i < N; ++i){
int A;
cin >> A;
--A; // 0-indexed に直しておく
if(A < 0)
front = i;
else
B[A] = i; // 人 i の直前が人 A ⇔ 人 A の直後が人 i
}
while(front < N){ // N になるまで(= 直後の人がいなくなるまで)直後に移動を繰り返す
cout << front + 1 << " ";
front = B[front];
}
cout << endl;
return 0;
}
投稿日時:
最終更新:
