loj#2324. 「清華集訓 2017」小 Y 和二叉樹(貪心+分類討論)

題面在這裏

題意:

給出一棵每個點度數不超過3的無根樹,節點編號爲1 ~n
你需要確定根和每個節點的左右兒子,使其成爲一棵二叉樹。
問所有可得到的二叉樹中中序遍歷字典序最小的樹的中序遍歷。
n1,000,000

做法:

這題似乎當時集訓隊全場ac
首先找出一個最小的度2 的點作爲最左邊的拐角點,也就是中序遍歷的第一個數。
然後把這個點當做根,f[u] 表示以u 爲根的子樹中中序遍歷開頭的最小值。
每次確定一下這個點u 連向的點當做u 的父親還是兒子,根據f[u] 來分類討論。

代碼:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
using namespace std;
typedef long long ll;
inline ll read() {
    char ch = getchar(); ll x = 0; int op = 1;
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') op = -1;
    for(; isdigit(ch); ch = getchar()) x = (x<<1)+(x<<3)+ch-'0';
    return x*op;
}
const int N = 2000010;
int n, cnt, flag, chk, tot, rt;
int head[N], d[N], ans[N], f[N];
struct edge {
    int to, nxt;
    edge() {}
    edge(int x, int y) { to = x; nxt = y; }
} e[N];
inline void addedge(int x, int y) { e[++ cnt] = edge(y, head[x]); head[x] = cnt; }
inline void dfs(int u, int lst) {
    for(int i = head[u], v; i; i = e[i].nxt) if((v = e[i].to) != lst) {
        dfs(v, u); f[u] = min(f[u], f[v]);//f[u]表示以u爲根的子樹中中序遍歷開頭的最小值
    }
}
inline void get(int u, int lst) {
    for(int i = head[u], v; i; i = e[i].nxt) if((v = e[i].to) != lst && f[v] == f[u]) get(v, u);
    ans[++ tot] = u;
    for(int i = head[u], v; i; i = e[i].nxt) if((v = e[i].to) != lst && f[v] != f[u]) get(v, u);
}
int main() {
    /*freopen("binary.in", "r", stdin);
    freopen("binary.out", "w", stdout);*/
    n = read();
    for(int i = 1; i <= n; i ++) {
        d[i] = read();
        for(int j = 1; j <= d[i]; j ++) {
            int x = read(); addedge(x, i);
        }
    }
    for(int i = 1; i <= n; i ++)
        if(d[i] <= 2) { rt = i; break; }
    for(int i = 1; i <= n; i ++) if(d[i] <= 2) f[i] = i; else f[i] = n+1;
    dfs(rt, 0);// for(int i = 1; i <= n; i ++) printf("%d ", f[i]); puts("");
    for(int u = rt, lst = 0; ; ) {
        ans[++ tot] = u; int c[5], ch = 0;
        for(int i = head[u], v; i; i = e[i].nxt) if((v = e[i].to) != lst) c[++ ch] = v;
        if(!ch) break;
        if(ch == 1) {
            if(f[c[1]] < c[1]) { get(c[1], u); break; }
            else { lst = u; u = c[1]; }
        }
        if(ch == 2) {
            if(f[c[1]] > f[c[2]]) swap(c[1], c[2]);
            get(c[1], u); lst = u; u = c[2];
        }
    }
    for(int i = 1; i <= n; i ++) printf("%d ", ans[i]);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章