zoukankan      html  css  js  c++  java
  • AcWing3422. 左孩子右兄弟(树形DP)

    对于一棵多叉树,我们可以通过 “左孩子右兄弟” 表示法,将其转化成一棵二叉树。

    如果我们认为每个结点的子结点是无序的,那么得到的二叉树可能不唯一。

    换句话说,每个结点可以选任意子结点作为左孩子,并按任意顺序连接右兄弟。

    给定一棵包含 N 个结点的多叉树,结点从 1 至 N 编号,其中 1 号结点是根,每个结点的父结点的编号比自己的编号小。

    请你计算其通过 “左孩子右兄弟” 表示法转化成的二叉树,高度最高是多少。

    注:只有根结点这一个结点的树高度为 0。

    例如如下的多叉树:

    QQ截图20210426100551.png

    可能有以下 3 种 (这里只列出 3 种,并不是全部) 不同的 “左孩子右兄弟”表示:

    QQ截图20210426100638.png

    其中最后一种高度最高,为 4。

    输入格式

    输入的第一行包含一个整数 N。

    以下 N−1 行,每行包含一个整数,依次表示 2 至 N 号结点的父结点编号。

    输出格式

    输出一个整数表示答案。

    数据范围

    对于 30% 的评测用例,1≤N≤20;
    对于所有评测用例,1≤N≤105。

    输入样例:

    5
    1
    1
    1
    2
    

    输出样例:

    4
    
    
    如果只看一个结点和它的儿子们的话,实际上结构是左-右-右-右...的样子,只需要把子树深度最大的儿子排在最右边即可,简单树上DFS搞定。考场上写了极其降智的贪心,果然不适合考试TAT
    
    #include <bits/stdc++.h>
    #define N 100005
    #define M 200005
    using namespace std;
    int n, head[N], ver[2 * M], Next[2 * M], tot = 0;
    int dp[N], cnt[N];
    void add(int x, int y) {
    	ver[++tot] = y, Next[tot] = head[x], head[x] = tot;
    }
    void dfs(int x, int pre) {
    	int maxx = 0;
    	dp[x] = 1;
    	for(int i = head[x]; i; i = Next[i]) {
    		int y = ver[i];
    		if(y == pre) continue;
    		dfs(y, x);
    		maxx = max(maxx, dp[y]);
    	}
    	dp[x] = cnt[x] + maxx;
    }
    int main() {
    	memset(dp, 0, sizeof(dp));
    	memset(cnt, 0, sizeof(cnt));
    	cin >> n;
    	for(int i = 2; i <= n; i++) {
    		int fa;
    		cin >> fa;
    		add(fa, i);
    		add(i, fa);
    		cnt[fa]++;
    	}
    	dfs(1, 0);
    	cout << dp[1];
    	return 0;
    }
    
  • 相关阅读:
    Java读写锁(ReentrantReadWriteLock)学习
    水平拆分和垂直拆分理解(未完)
    MySQL 主从复制
    sharding-JDBC 实现读写分离
    Linux查看程序端口占用情况
    sharding-jdbc 实现分表
    MySQL explain
    MySQL的七种join
    MySQL建立高性能索引策略
    Nginx企业级优化
  • 原文地址:https://www.cnblogs.com/lipoicyclic/p/14841395.html
Copyright © 2011-2022 走看看