zoukankan      html  css  js  c++  java
  • 树的直径与最近公共祖先

    1.树的直径

    1.1 树形DP求树的直径

    1.1.2 思路:设d[x]为从结点x出发走以x为根的子树,能够达到最远结点的距离。设x的子节点为y1,y2,y3...yt,edge(x,yi)表示边的权重,那就有:d[x] = max{ d[yi] + edge(x,yi) }(i <= i <=t)

    接下来设经过x的最长链的长度为F[x],那么整棵树的直径就是max{F[x]} (1 <= x <= n)。F[x]可以由四个部分构成:x走yi子树的最远距离,x走yj子树的最远距离,x到yi的距离,x到yj的距离。也就是:F[x] = maxn{ d[yi] + d[yj] + edge(x,yi) + edge(x,yj) }

    由于我们已经用d[x]保存从结点x出发走向 “以yj为根的子树(j < i)” ,能够达到的最远距离,这个距离就是max{ d[yj] + edge(x,yj) }。所以,我们只要先用d[x] + d[yi] + edge(x,yi)来更新F[x],再用d[yi] + edge(x,yi) 来更新d[x]即可。

    1.2 两次BFS求树的直径

    1.2.1 思路:通过两次BFS求出树的直径,更容易计算出直径上的具体结点。做法包括两步:

    1. 从任意一个节点出发,通过BFS或DFS对树进行一次遍历,求出与出发点距离最远的节点记为p
    2. 从节点p出发,通过BFS或DFS再进行一次遍历,求出与p距离最远的节点,记为q

    那么p到q的路径就是树的一条直径。因为p一定是直径的一端,而同理q也是树的另一端,故算法成立。

    1.2.2 代码示例:

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<vector>
    #include<cstring>
    using namespace std;
    const int maxn = 100005;
    vector<int> G[maxn];//用来存放有向边 
    int d[maxn];//存放从起始点到该节点的距离 
    int p[maxn];//父节点 
    bool vis[maxn];//是否已访问 
    int BFS(int s){
    	memset(vis,false,sizeof vis);
    	memset(d,0,sizeof d);
    	memset(p,0,sizeof p);
    	int ans;//当前最大距离时的结点 
    	int maxlen = -1;//最大距离 
    	queue<int> q;
    	q.push(s);
    	vis[s] = true;
    	while(!q.empty()){
    		int x = q.front();
    		q.pop();
    		for(int i = 0;i < G[x].size();i++)	if(!vis[G[x][i]]){
    			d[G[x][i]] = d[x]+1;
    			p[G[x][i]] = x;
    			q.push(G[x][i]);
    			vis[G[x][i]] = true;
    		}
    		if(d[x] > maxlen){
    			ans = x;
    			maxlen = d[x];
    		}
    	}
    	return ans;//返回最大距离的结点编号 
    }

    2.最近公共祖先(LCA)

    2.1 定义:

    给定一颗有根树,若节点z既是节点x的祖先,也是节点y的祖先,则称z是x,y的公共祖先。在x,y所有的公共祖先中,深度最大的一个称为x,y的最近公共祖先,记为LCA(x,y)。

    2.2 向上标记法:

    2.2.1 思路:

    1. 从x向上走到根节点,并标记所有经过的节点
    2. 从y向上走到根节点,当第一次遇到已标记的节点时,就找到了LCA(x,y)

    2.2.2 复杂度分析:最坏为O(n)

    2.3 树上倍增法:

    2.3.1 模板: 最近公共祖先模板

    2.3.2 复杂度分析:每次询问复杂度为O(logn)

    2.4 LCA的Tarjan算法:

    2.4.1 模板:

    2.4.2 复杂度分析:离线算法,需要把m次询问一次性读入,统一输出。时间复杂度O(n+m)

    《算法竞赛进阶指南——李煜东》P341

  • 相关阅读:
    【Python学习笔记之三】lambda表达式用法小结
    Cisco Packet Tracer 6.0 实验笔记
    Kali Linux 下安装中文版输入法
    kali 2018.1安装教程
    Kali Linux菜单中各工具功能大全
    互联网电商购物车架构演变案例
    互联网业务场景下消息队列架构
    物流系统高可用架构案例
    高并发下海量容器案例一
    客服系统微服务架构的演化
  • 原文地址:https://www.cnblogs.com/long98/p/10352194.html
Copyright © 2011-2022 走看看