D. Numbers on Tree(構造)【CF 1287】

傳送門ios

思路:算法

咱們須要抓住惟一的重要信息點"ci",個人作法也是在猜測和嘗試中得出的,以後再驗證算法的正確性。spa

咱們在構造中發現,若是樹上出現了相同的數字,則會讓樹的構造變得不清晰。code

咱們嘗試用不一樣的數值a[1]~a[n]去構造樹,咱們惟一知道的信息就是"ci",若是a[1]~a[n] = 1~n(從小到大排序),則咱們容易肯定root的數值id[root] = a[c[root] + 1]。爲何?由於咱們有1~n這n個數字,若是咱們id[root] = a[c[root] + 1],則root下面的點,不管怎麼放置這n-1個數字都知足c[root]。若是該root的左邊第一個son節點的c[x] = t,則id[x]爲第c[x] + 1個數字(由於id[root]被使用了)好像也行的通(紅字帶入也行得通),而後我按着從左開始的dfs序模擬,發現問題就解決了,這樣的方法是行的通的。爲何?模擬了以後才發現,由於咱們選的是不一樣的數字,咱們若是按着從左的dfs序一個個的解決子樹,只要有足夠的不一樣數字,則該方法必定是能夠構造出當前子樹的信息(帶入紅字理解),即子樹之間獨立不影響。用這個構造方法以前只須要先判斷下全部的ci是否是合法,即該點下面若是隻有x個數字,c[now]>x就是不合法的。代碼下面有個樣例,模擬下就理解了。blog

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#include <string>
#include <map>
#include <set>

using namespace std;

const int N = 2e3 + 10;
vector<int > E[N];
set<int > hav;
int son[N], id[N];
int error;

int fun (int now, int pre)
{
    int sn = 0;
    for(auto to : E[now]) {
        if(to == pre) continue;
        sn += fun(to, now);
    }

    if(son[now] - 1 > sn) error = 1; ///判斷ci是否是合法
    return sn + 1;
}

void dfs (int now, int pre)
{
    if(son[now] > hav.size()) { error = 1; return; }
    else {
        int tot = 0;
        for(auto& x: hav) {
            ++tot;
            if(tot == son[now]) {
                id[now] = x;
               // cout << x << endl;
                hav.erase(x);
                break;
            }
        }
    }

    for(auto to : E[now]) {
        if(to == pre) continue;
        dfs(to, now);
        if(error) return;
    }
}

void solve()
{
    int n, root;
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) {
        int x, cnt;
        scanf("%d%d", &x, &cnt);
        if(x != 0) {
            E[i].push_back(x);
            E[x].push_back(i);
        } else root = i;
        son[i] = cnt + 1;///第幾個數字
    }

    for(int i = 1; i <= n; ++i) { hav.insert(i); }

    error = 0;
    fun(root, 0);
    if(error) {
        printf("NO\n");
        return;
    }
    dfs(root, 0);
    if(error) { printf("NO\n"); }
    else {
        printf("YES\n");
        for(int i = 1; i <= n; ++i) { printf("%d ", id[i]); }
        printf("\n");
    }
}

int main()
{

    solve();

    return 0;
}
/*
13
0 5
1 2
2 0
2 1
4 0
4 1
6 0
6 0
1 1
9 0
9 2
11 0
11 0

*/
相關文章
相關標籤/搜索