ちゃんと証明しようとすると、結構大変!
問題概要
人の生徒がいて、生徒 の身長は である。
これらの生徒を 2 人ずつ 組に分けて、どの組も身長差が 以下となるようにしたい。
そのようなことが可能かどうかを判定せよ。
制約
考えたこと
このようなとっかかりの難しい問題では、「まず最小値に着目する」とよいことが多いです。
今回は、まず「身長が最小の生徒と誰を組ませるべきか」を考えてみましょう。考えやすくするために、生徒の身長を適宜ソートして
を満たすとします。今考えていることは、 とペアを組ませるべきは誰か? となります。直感的には、 と組ませるのが良さそうに感じるでしょう。そうすれば、 はペアを組む相手との身長差を最小にできます。
ここで気になることは、 のために を使ったが、他の場面でも を使いたくなることってないんだろうか???ということです。もし、そのような場面があるのだとしたら、 と を組ませるのが良いという結論が嘘だということです。
......実は、今回は、 のために を割り当ててしまってよいということが証明できます!!!!!
今回の問題程度の複雑さであれば、わざわざ証明しなくても「きっとそうに違いない」と確信が持てれば、その解法を提出してみてもよいえしょう。しかし、より高難易度の問題に挑む際には、証明の考え方を身につけておくことはとても重要です。
のために を割り当てて良いことの証明
それでは、 のために を割り当てると考えて問題ないことを証明してみましょう!
もし、条件を満たす組分けが存在して、
- と ()
- と ()
がペアになっているとしましょう。このとき、実は
- と
- と
というように組み替えをしても条件を満たします。つまり、 と は必ず組むことにしてもよいということが言えるわけです。
まず、 ですから、
となります。さらに、
- の場合:
- ( より)
- の場合:
- ( より)
となり、いずれも を満たします。以上より、示せました。
もとの問題に戻り
ここまでの議論から、 と は必ず組むとしてよいことが分かりました。
そうすると、残りの を組分けする問題へと帰着されます。そして、また同様の議論によって、 と は必ず組むとしてよいことが言えます。
以上の手続きを繰り返すことで、結局次のことが言えます。
となるように並び替えたとする。このとき、
をすべて満たすならば "Yes"、そうでなければ "No" である。
コード
#include <bits/stdc++.h> using namespace std; int main() { int N, D; cin >> N >> D; vector<int> A(N*2); for (int i = 0; i < N*2; i++) cin >> A[i]; sort(A.begin(), A.end()); bool res = true; for (int i = 0; i < N*2; i += 2) { if (A[i+1] - A[i] > D) res = false; } cout << (res ? "Yes" : "No") << endl; }