AtCoder Beginner Contest 015のC問題 「高橋くんのバグ探し」
C - 高橋くんのバグ探し
入力:
出力: 条件を満たすなら 'Found' 、そうでなければ 'Nothing'
制約:
入力の下 行のそれぞれから、整数を一つずつ選びます。選ばれた整数全ての排他的論理和(XOR)の値が になるような組があったら 'Found' 、そうでなければ 'Nothing' を出力します。
この問題で難しいのは、各行から整数を選んでいくところです。簡単に考えられる方法としては、 重ループを書くことで全探索することが挙げられますが、 それぞれの場合について実装するのは大変です(仮に のときも動くプログラムのことを考えると、私は正気を保ちつつコードを書ける自信がありません)。このような場合、再帰関数を実装するのが正攻法です。
ここでは、「配列を受け取り、その長さが より小さいときは配列に のいずれかを追加する。そうでないときは、その配列を用いて排他的論理和の値の判定を行い、 XOR が 0 になる組があれば true を返す」関数を考えます。
一つの関数を実装することで、 通りの整数の組を検証できているところがポイントです。
なお、D言語では arr ~ elem で「配列 arr の末尾に要素 elem を追加した配列」を得ることができます。
また、 foreach(i, v; arr) では i に添字、 v に arr[i] が代入されています。
void main() { /* 入力 */ auto ip = readAs!(int[]), N = ip[0], K = ip[1]; auto T = readMatrix!int(N, K); bool check(int[] arr) { if(arr.length < N) { foreach(i; 0..K) { if(check(arr ~ i)) return true; } return false; } int tmp = 0; foreach(i, v; arr) { tmp ^= T[i][v]; } return tmp == 0; } if(check([])) writeln("Found"); else writeln("Nothing"); }
一つでもXORが 0 になる組がある場合は 'Found' になることに注意して実装します。
一文にまとめると「再帰関数を書いて深さ優先探索」です。
感想: AtCoder Problems の Recommendations から一問解いてみました。Difficulty は 1172 となっていますが、現在のABCで出題したらきっと茶パフォ程度になるのかな〜と思います。