CF1833G Ksyusha and Chinchilla

发布时间 2023-09-09 01:43:53作者: 空白菌

题目链接

题解

知识点:贪心,树形dp。

\(3 \not \mid n\) 时,显然无解。

考虑一种贪心策略,从叶子节点往上只,要以当前节点为根的子树大小能被 \(3\) 整除,就立刻切除这棵子树,若最后切除次数刚好为 \(\dfrac{n}{3} - 1\) ,则有解。

考虑证明:

  1. 显然,若根据我们的策略成功划分,则一定满足条件,即有解。
  2. 若不满足,则一定存在一个子树除掉满足我们策略的部分后,仍然剩余 \(>3\) 个节点,此时子树的每个子树深度不会超过 \(2\) ,且一定没有分叉,是无法进行任何切割的,因此无解。

时间复杂度 \(O(n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

vector<pair<int, int>> g[200007];

int sz[200007];
vector<int> ans;
void dfs(int u, int fa) {
    sz[u] = 1;
    for (auto [v, id] : g[u]) {
        if (v == fa) continue;
        dfs(v, u);
        sz[u] += sz[v];
        if (sz[v] % 3 == 0) ans.push_back(id);
    }
}

bool solve() {
    int n;
    cin >> n;
    ans.clear();
    for (int i = 1;i <= n;i++) g[i].clear();
    for (int i = 1;i <= n - 1;i++) {
        int u, v;
        cin >> u >> v;
        g[u].push_back({ v,i });
        g[v].push_back({ u,i });
    }

    if (n % 3) return false;

    dfs(1, 0);
    if (ans.size() != n / 3 - 1) return false;
    cout << n / 3 - 1 << '\n';
    for (auto id : ans) cout << id << ' ';
    cout << '\n';
    return true;
}

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--) {
        if (!solve()) cout << -1 << '\n';
    }
    return 0;
}