图论—树的直径(树形DP、BFS)

2024-03-28 05:12
文章标签 dp 图论 bfs 直径 树形

本文主要是介绍图论—树的直径(树形DP、BFS),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

树的直径——树形 D P 、两次 B F S \Huge{树的直径——树形DP、两次BFS} 树的直径——树形DP、两次BFS

文章目录

  • 树形DP
  • 两次BFS

不再详细解释代码,只记录完整模板。

树形DP

可以计算负权边。

时间复杂度: O ( n ) O(n) O(n)

D [ x ] D[x] D[x]表示从节点 x x x出发走向以 x x x为根的字数,能够到达的最远节点的距离;设 y i y_i yi表示子节点, e d g e ( x , y ) edge(x,y) edge(x,y)表示边权,则有:

D [ x ] = m a x 1 ≤ i ≤ t ( D [ y i ] + e d g e ( x i , y i ) ) D[x]=max_{1\le i\le t}(D[y_i]+edge(x_i,y_i)) D[x]=max1it(D[yi]+edge(xi,yi))

设F[x]为经过节点x的最长链长度,则有:

F [ x ] = m a x 1 ≤ j < i ≤ t ( D [ y i ] + D [ y j ] + e d g e ( x , y i ) + e d g e ( x , y j ) ) F[x]=max_{1\le j<i\le t}(D[y_i]+D[y_j]+edge(x,y_i)+edge(x,y_j)) F[x]=max1j<it(D[yi]+D[yj]+edge(x,yi)+edge(x,yj))

int res, n, b[N], d[N];
vector<PII> a[N];
void dp(int x) {b[x] = 1;for(int i = 0; i < a[x].size(); i ++ ) {int t = a[x][i].fi, u = a[x][i].se;if(b[t]) continue;dp(t);res = max(res, d[x] + d[t] + u);d[x] = max(d[x], d[t] + u);}
}void Solved() {cin >> n;for (int i = 0; i < n - 1; ++i) {int x, y, z; cin >> x >> y >> z;a[x - 1].push_back({y - 1, z});a[y - 1].push_back({x - 1, z});}dp(0);	cout << res << endl;
}

两次BFS

实现最长直径长度,计算出直径上的具体节点。

无法计算负权边!!!

时间复杂度: O ( n ) O(n) O(n)

struct Node {int id, distance;};// 结点
struct Edge {int to, weight;};  // 边vector<vector<Edge>> tree; //用于存储树的结构
vector<bool> visited;      //标记
vector<int> parent;        //存放父节点Node bfs(int start) {// 第一次 BFS,从任意结点开始找到最远的结点queue<Node> q;visited.assign(tree.size(), false);q.push({start, 0});visited[start] = true;Node farthest = {start, 0};while (!q.empty()) {Node current = q.front(); q.pop();if (current.distance > farthest.distance) farthest = current;for (const Edge& edge : tree[current.id]) {if (!visited[edge.to]) {visited[edge.to] = true;q.push({edge.to, current.distance + edge.weight});parent[edge.to] = current.id; // 保存父节点信息}}}return farthest;
}vector<int> diameter() {// 第二次 BFS,从最远的结点开始找到直径的另一端Node start = bfs(0);Node end = bfs(start.id);vector<int> path;path.push_back(end.id);// 从 end.id 向上回溯到 start.id,得到直径上的所有节点int current = end.id;while (current != start.id) {current = parent[current]; // 根据父节点数组回溯path.push_back(current);}reverse(path.begin(), path.end());path.push_back(end.distance);   //将最长直径一并返回return path;
}int main() {int n; cin >> n;tree.resize(n); parent.resize(n, -1);for (int i = 0; i < n - 1; ++i) {int x, y, z; cin >> x >> y >> z;tree[x - 1].push_back({y - 1, z});tree[y - 1].push_back({x - 1, z});}vector<int> path = diameter();cout << path.back() << endl;    //输出最长直径path.pop_back();                //将答案删除for (int node : path)         //输出最长直径具体节点cout << node + 1 << " ";return 0;
}

这篇关于图论—树的直径(树形DP、BFS)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/854534

相关文章

hdu1254(嵌套bfs,两次bfs)

/*第一次做这种题感觉很有压力,思路还是有点混乱,总是wa,改了好多次才ac的思路:把箱子的移动当做第一层bfs,队列节点要用到当前箱子坐标(x,y),走的次数step,当前人的weizhi(man_x,man_y),要判断人能否将箱子推到某点时要嵌套第二层bfs(人的移动);代码如下:

hdu4826(三维DP)

这是一个百度之星的资格赛第四题 题目链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1004&cid=500 题意:从左上角的点到右上角的点,每个点只能走一遍,走的方向有三个:向上,向下,向右,求最大值。 咋一看像搜索题,先暴搜,TLE,然后剪枝,还是TLE.然后我就改方法,用DP来做,这题和普通dp相比,多个个向上

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

hdu4865(概率DP)

题意:已知前一天和今天的天气概率,某天的天气概率和叶子的潮湿程度的概率,n天叶子的湿度,求n天最有可能的天气情况。 思路:概率DP,dp[i][j]表示第i天天气为j的概率,状态转移如下:dp[i][j] = max(dp[i][j, dp[i-1][k]*table2[k][j]*table1[j][col] )  代码如下: #include <stdio.h>#include

zoj3820(树的直径的应用)

题意:在一颗树上找两个点,使得所有点到选择与其更近的一个点的距离的最大值最小。 思路:如果是选择一个点的话,那么点就是直径的中点。现在考虑两个点的情况,先求树的直径,再把直径最中间的边去掉,再求剩下的两个子树中直径的中点。 代码如下: #include <stdio.h>#include <string.h>#include <algorithm>#include <map>#

usaco 1.1 Broken Necklace(DP)

直接上代码 接触的第一道dp ps.大概的思路就是 先从左往右用一个数组在每个点记下蓝或黑的个数 再从右到左算一遍 最后取出最大的即可 核心语句在于: 如果 str[i] = 'r'  ,   rl[i]=rl[i-1]+1, bl[i]=0 如果 str[i] = 'b' ,  bl[i]=bl[i-1]+1, rl[i]=0 如果 str[i] = 'w',  bl[i]=b

uva 10154 DP 叠乌龟

题意: 给你几只乌龟,每只乌龟有自身的重量和力量。 每只乌龟的力量可以承受自身体重和在其上的几只乌龟的体重和内。 问最多能叠放几只乌龟。 解析: 先将乌龟按力量从小到大排列。 然后dp的时候从前往后叠,状态转移方程: dp[i][j] = dp[i - 1][j];if (dp[i - 1][j - 1] != inf && dp[i - 1][j - 1] <= t[i]

uva 10118 dP

题意: 给4列篮子,每次从某一列开始无放回拿蜡烛放入篮子里,并且篮子最多只能放5支蜡烛,数字代表蜡烛的颜色。 当拿出当前颜色的蜡烛在篮子里存在时,猪脚可以把蜡烛带回家。 问最多拿多少只蜡烛。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cs

uva 10069 DP + 大数加法

代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <queue>#include <map>#include <cl

uva 10029 HASH + DP

题意: 给一个字典,里面有好多单词。单词可以由增加、删除、变换,变成另一个单词,问能变换的最长单词长度。 解析: HASH+dp 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#inc