Codeforces #596 div1 D/div2 F Tree Factory

题目链接:https://codeforces.com/contest/1246/problem/D

题意:给一棵有n个节点的有根树,要求用一棵有n个节点的竹子构造这棵树,竹子是一种每个节点只有一个子节点,只有一个没有子节点的节点的有根树。可以对竹子进行,若节点v不为根且v的父节点不为根,则将v和v的子树移到v的父节点的父节点上的操作。竹子的每个节点的编号可以自定义,问最少多少次操作会使竹子变为这棵树,输出竹子的编号,操作次数和每次操作的操作对象。

做法:很(写)有(不)意(出)思(来)的构造。首先得出结论答案的下界是n-1-dep(dep为树的深度),因为每次操作只会使一个子树内的点深度-1,也就是最多使最大深度-1。反过来思考,如果给一棵竹子,用一棵树去构造,每次操作选择一个子树将它沿某条边向下移动,则移动的次数必定为n-1-dep,因此,操作的次数也必定为n-1-dep。构造过程中,将树中最深的节点所在的链放在最后,此处参考了杜老师的代码,非常精妙,具体实现见代码。

参考代码:

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;
const int MAXN = 100005;
vector<int> sequence, operation, son[MAXN];
int cnt, heavyson[MAXN], dep[MAXN], father[MAXN], n;

void dfs(int now)
{
    sequence.push_back(now);
    for (int i = 0; i < cnt; ++i)
        operation.push_back(now);
    cnt = 0;
    for (auto v:son[now])
        if (v != heavyson[now])
            dfs(v);
    if (heavyson[now])
        dfs(heavyson[now]);
    cnt++;
}

int main()
{
    cin >> n;
    dep[0] = 1;
    for (int i = 1; i < n; ++i)
    {
        cin >> father[i];
        son[father[i]].push_back(i);
        dep[i] = dep[father[i]] + 1;
    }
    int maxdep = max_element(dep, dep + n) - dep;
    int heavysonnode = maxdep;
    while (heavysonnode)
    {
        heavyson[father[heavysonnode]] = heavysonnode;
        heavysonnode = father[heavysonnode];
    }
    dfs(0);
    for (int i = 0; i < n; ++i)
    {
        if (i != 0)
            cout << " ";
        cout << sequence[i];
    }
    cout << endl;
    cout << (int) operation.size() << endl;
    for (int i = 0; i < (int) operation.size(); ++i)
    {
        if (i != 0)
            cout << " ";
        cout << operation[i];
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/mapleaves/p/11778007.html