Learning Algorithms

アルゴリズムの勉強メモ

Atcoder AGC #005 C. Tree Restoring

Atcoder AGC #005 C. Tree Restoring

C: Tree Restoring - AtCoder Grand Contest 005 | AtCoder

頂点iからみて最も遠い点までの距離がa[i]として与えられるので、そのような木が構成可能かを答える問題。とりあえずa[i]の最小値が、3個以上ある場合は構成不可能であることが簡単に示せる。そこで、その最小値minを根として根付き木を考えた。まず、minが1個のときは、minから少なくとも2つの辺が出ていて、(minがそれ唯一であることを考慮すると)どちらの最大の深さもminであるような木でなければならないことに気づく。そのような木を構成するためにはまず、m< a[i] <= 2mであるようなa[i]がそれぞれ最低2個あるkとが必要である。そしてa[i] > mであるようなa[i]がないことも確認すれば、これで判定が終わる。なぜなら、他のすべてのm < a[i] <= 2mに関して、それがa[i] = m + kを満たすとすると、左右どちらかの深さkの位置に新しい子としてくっつけてやれば、他のどの頂点の値も変えることなく、a[i] = m + kとなるように木を拡大できるからである。一方、minが2個あるときは、まずminを根にし、その隣にもminをつけ(これを仮に左の子につけるとする)、左の深さをmin、右の深さをmin - 1にすることで、上と同様のことができる。このとき、条件がm < a[i] < 2mに変わることに気をつけること。

#include "bits/stdc++.h"
using namespace std;

int print(bool ok) {
        if (ok) cout << "Possible" << endl;
        else cout << "Impossible" << endl;
        return 0;
}

int main() {
        int n, a;
        cin >> n;
        int mi = 110;
        int cnt[200] = { 0 };
        for (int i = 0; i < n; i ++) { 
                cin >> a;
                cnt[a] ++;
                mi = min(mi, a);
        }
        if (cnt[mi] > 2) return print(0);
        for (int i = mi + 1; i < 2 * mi + (cnt[mi] == 1 ? 1 : 0); i ++) if (cnt[i] < 2) return print(0);
        for (int i = 2 * mi + (cnt[mi] == 1 ? 1 : 0); i < 200; i ++) if (cnt[i] > 0) return print(0);
        return print(1);
}

700点前後の問題が自力で解けるようになってきた感じが嬉しい。