关于树

树是由一个集合以及在该集合上定义的一种关系构成的,集合中的元素称为树的结点,所定义的关系称为父子关系。父子关系在树的结点之间建立了一个层次结构,在这种层次结构中有一个结点具有特殊的地位,这个结点称为该树的根结点。

树的一些名词

节点的度:一个节点含有的子树的个数称为该节点的度;

叶节点或终端节点:度为0的节点称为叶节点;

非终端节点或分支节点:度不为0的节点;

双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;

孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;

兄弟节点:具有相同父节点的节点互称为兄弟节点;

树的度:一棵树中,最大的节点的度称为树的度;

节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;

树的高度或深度:树中节点的最大层次;

堂兄弟节点:双亲在同一层的节点互为堂兄弟;

节点的祖先:从根到该节点所经分支上的所有节点;

子孙:以某节点为根的子树中任一节点都称为该节点的子孙。

森林:由m(m >= 0)棵互不相交的树组成的集合称为森林;

树的几种存储

1.双亲表示法

2.孩子表示法

3.邻接表

树的一些操作

1.树的节点计数(入门OJ1570)

这个很简单,直接做就好了。

代码:

#include<bits/stdc++.h>
using namespace std;
struct node {
    int v, next;
} e[50010 * 2];
int p[50010], k;
int cnt[50010];
int vis[50010];
int n;
 
void read(int &x) {
    char ch; bool ok;
    for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
    for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
}
 
void init() {
    memset(p, -1, sizeof(p));
}
 
void insert(int u,int v) {
    e[k].v = v;
    e[k].next = p[u];
    p[u] = k++;
}
 
void dfs(int u) {
    vis[u] = 1;
    for(int i = p[u]; i + 1; i = e[i].next) {
        if(!vis[e[i].v]) {
            dfs(e[i].v);
            cnt[u] += cnt[e[i].v];
        }
    }
}
 
int main() {
    init();
    cin >> n;
    for(int i = 1; i <= n; i++) {
        cnt[i] = 1;
    }
    int u, v;
    for(int i = 1; i < n; i++) {
        read(u);read(v);
        insert(u, v);
        insert(v, u);
    }
    dfs(1);
    for(int i = 1; i <= n; i++) {
        printf("%d\n", cnt[i] - 1);
    }
    return 0;
}

2.树的深度计数(入门OJ5962)

这题也很简单,dfs跑一跑就好了

代码:

#include <bits/stdc++.h>
using namespace std;
int k, n, s;
int pre[100001], now[100001], son[100001], ans[100001];
bool vis[50001];
void insert(int a, int b) {
    pre[++k] = now[a];
    now[a] = k;
    son[k] = b;
}
void dfs(int u, int r) {
    vis[u] = 1;
    ans[u] = r + 1;
    int ans = 0, m = 0;
    for(int i = now[u]; i; i = pre[i]) {
        int k = son[i];
        if(!vis[k])
            dfs(k, r + 1);
    }
}
int main() {
    int a, b;
    scanf("%d", &n);
    for(int i = 1; i <= n - 1; i++) {
        scanf("%d%d", &a, &b);
        insert(a, b);
        insert(b, a);
    }
    dfs(1, -1);
    for(int i = 1; i <= n; i++)
        printf("%d\n", ans[i]);
    return 0;
}

3.树的重心(入门OJ1596)

树的重心也叫树的质心。简单来说就是,你删掉某个点后剩下的最大的树最小,这个点就是重心。

代码:

//一个重心 
#include<iostream>
using namespace std;
struct node {
	int v, nxt;
} e[100010];

int n, mi;
int p[50010], num;
int dp[50010];

bool vis[50010];

void insert(int u, int v) {
	e[++num].v = v;
	e[num].nxt = p[u];
	p[u] = num;
}

void dfs(int u, int f) {
	dp[u] = 1;
	int mx = 0;
	for (int i = p[u]; i; i = e[i].nxt) {
		if (e[i].v != f) {
			dfs(e[i].v, u);
			dp[u] += dp[e[i].v];
			mx = max(mx, dp[e[i].v]);
		}
	}
	mx = max(mx, n - dp[u]);
	if (mx < mi) {
		mi = mx;
	}
}

int main() {
	cin >> n;
	for (int i = 1; i < n; i++) {
		int x, y;
		cin >> x >> y;
		insert(x, y);
		insert(y, x);
	}
	mi = 1e9;
	dfs(1, 0);
	cout << mi << endl;
}
//所有重心 
#include<iostream>
using namespace std;
struct node {
	int v, nxt;
} e[100010];

int n, mi;
int p[50010], num;
int dp[50010];
int mx[50010];
bool vis[50010];

void insert(int u, int v) {
	e[++num].v = v;
	e[num].nxt = p[u];
	p[u] = num;
}

void dfs(int u, int f) {
	dp[u] = 1;
	for (int i = p[u]; i; i = e[i].nxt) {
		if (e[i].v != f) {
			dfs(e[i].v, u);
			dp[u] += dp[e[i].v];
			mx[u] = max(mx[u], dp[e[i].v]);
		}
	}
	mx[u] = max(mx[u], n - dp[u]);
	mi = min(mi, mx[u]);
}

int main() {
	cin >> n;
	for (int i = 1; i < n; i++) {
		int x, y;
		cin >> x >> y;
		insert(x, y);
		insert(y, x);
	}
	mi = 1e9;
	dfs(1, 0);
	for (int i = 1; i <= n; i++) {
		if (mx[i] == mi) {
			cout << i << endl;
		}
	}
}

友情提示:注意输出格式

4.树的直径(入门OJ1584)

直径嘛,顾名思义,就是在树上找到两个点满足这两点间的距离最远(距离定义为连接两点的路径边权之和),这个距离就叫做树的直径。

代码:

#include<bits/stdc++.h>
using namespace std;
int n, m, cnt, maxx;
int to[100010], nxt[100010], val[100010];
int head[50010], s[50010];
char str[5];
void insert(int a, int b, int c) {
    to[cnt] = b;
    val[cnt] = c;
    nxt[cnt] = head[a];
    head[a] = cnt++;
}
void dfs(int x, int fa) {
    maxx = (s[maxx] < s[x]) ? x : maxx;
    for(int i = head[x]; ~i; i = nxt[i]) {
        if(to[i] != fa) {
            s[to[i]] = s[x] + val[i];
            dfs(to[i], x);
        }
    }
}
int main() {
    scanf("%d%d", &n, &m);
    int a, b, c;
    memset(head, -1, sizeof(head));
    for(int i = 1; i <= m; i++){
        scanf("%d%d%d%s", &a, &b, &c, &str);
        insert(a, b, c);
        insert(b, a, c);
    }
    dfs(1, 0);
    s[maxx] = 0;
    dfs(maxx, 0);
    printf("%d", s[maxx]);
    return 0;
}

差不多就是这样

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值