B - ネットワーク構築 / Network Construction 解説 by admin
Claude 4.6 Opus (Thinking)概要
\(N\) 台のコンピュータからいくつかを選び、すべてのポートを使い切る木構造のネットワークを構築できるかを判定する問題。ポート数 \(0\) のコンピュータが存在するか、ポート数 \(1\) のコンピュータが \(2\) 台以上存在するかで判定できる。
考察
木の性質を利用する
\(k\) 台のコンピュータで木を構成する場合、以下が成り立ちます: - 辺(ケーブル)の本数は \(k-1\) - 各頂点の次数(ポート使用数)の合計 = \(2(k-1)\)
つまり、選んだコンピュータのポート数を \(a_1, a_2, \ldots, a_k\) とすると、\(\sum a_i = 2(k-1)\) が必要です。
実現可能性の古典的結果
正の整数列 \(d_1, d_2, \ldots, d_k\) が \(\sum d_i = 2(k-1)\) を満たすなら、その次数列を持つ木が必ず存在します(Prüfer列の性質から導かれる古典的結果)。
場合分けによる網羅
\(k = 1\) の場合: \(A_i = 0\) のコンピュータを \(1\) 台選べばOK → \(cnt_0 \geq 1\)
\(k = 2\) の場合: \(a_1 + a_2 = 2\) かつ \(a_1, a_2 \geq 1\) なので、\(a_1 = a_2 = 1\) → \(cnt_1 \geq 2\)
\(k \geq 3\) の場合: ここが鍵です。選んだ値はすべて \(\geq 1\) で、合計が \(2(k-1)\) である必要があります。
- もし選んだ値がすべて \(\geq 2\) なら、合計 \(\geq 2k > 2(k-1)\)。不可能!
- もし選んだ値のうちちょうど \(1\) つが \(1\)、残りが \(\geq 2\) なら、合計 \(\geq 1 + 2(k-1) = 2k-1 > 2(k-1)\)。不可能!
- \(2\) つ以上が \(1\) なら可能性があるが、これは \(cnt_1 \geq 2\) を要求する(この場合、単に \(2\) 台の \(A_i = 1\) を選ぶ方が簡単)。
結論
答えが Yes となる必要十分条件は:
\[cnt_0 \geq 1 \quad \text{または} \quad cnt_1 \geq 2\]
アルゴリズム
- 入力を読み込み、\(A_i = 0\) の個数 (\(cnt_0\)) と \(A_i = 1\) の個数 (\(cnt_1\)) を数える。
- \(cnt_0 \geq 1\) または \(cnt_1 \geq 2\) なら
Yes、そうでなければNoを出力。
具体例:
- \(A = [0, 3, 2]\):\(cnt_0 = 1 \geq 1\) → Yes(コンピュータ1を1台だけ選ぶ)
- \(A = [1, 1, 5]\):\(cnt_1 = 2 \geq 2\) → Yes(コンピュータ1と2を選び、1本のケーブルで接続)
- \(A = [2, 3]\):\(cnt_0 = 0, cnt_1 = 0\) → No
計算量
- 時間計算量: \(O(N)\)(配列を1回走査するだけ)
- 空間計算量: \(O(1)\)(カウンタのみ保持)
実装のポイント
\(A_i\) の値が最大 \(10^9\) なので、入力は
long longで受け取る。条件判定は非常にシンプルで、カウントさえ正確に行えば良い。
\(k \geq 3\) の場合を個別に探索する必要がないことが、この問題の本質的な気づきである。
ソースコード
#include <bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N;
cin >> N;
int cnt0 = 0, cnt1 = 0;
for(int i = 0; i < N; i++){
long long a;
cin >> a;
if(a == 0) cnt0++;
if(a == 1) cnt1++;
}
if(cnt0 >= 1 || cnt1 >= 2){
cout << "Yes" << endl;
} else {
cout << "No" << endl;
}
return 0;
}
この解説は claude4.6opus-thinking によって生成されました。
投稿日時:
最終更新: