首页 > 其他分享 >Roads in the North POJ - 2631 - 树的直径/树形dp

Roads in the North POJ - 2631 - 树的直径/树形dp

时间:2023-09-19 15:12:07浏览次数:54  
标签:North idx int 2631 dfs add POJ d2 d1

题意:给出一棵无向树,求树的直径,即树上两点之间的最长距离

分析:两种解法

解法1:先任取一个点,找到距离该点最远的点u,再找到距离u最远的点v,那么u和v之间的路径就是一条直径。

证明:只要找到了树的直径的一个端点,再从该点找到最远点就一定是直径的另一个端点。所以只需要证明第一次找到的最远点u就是其中一个端点即可。
image

上述证明过程建立在所有路径均不为负的前提下,如果树上存在负权边,则上述证明不成立。

点击查看代码
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10, INF = 0x3f3f3f3f;
struct T {
    int v, w, nx;
} g[N];
int h[N], idx, temp, ans;
void add(int u, int v, int w) {
    g[++idx] = {v, w, h[u]}, h[u] = idx;
}
bool st[N];
void dfs(int u, int s) {
    st[u] = 1;
    if (ans < s)
        temp = u, ans = s;
    for (int i = h[u]; i; i = g[i].nx) {
        int v = g[i].v, w = g[i].w;
        if (!st[v])
            dfs(v, s + w);
    }
}
int main() {
    int x, y, z;
    while (cin >> x >> y >> z) {
        add(x, y, z), add(y, x, z);
    }
    dfs(1, 0);
    memset(st, 0, sizeof(st)), dfs(temp, 0);
    cout << ans;
    return 0;
}

解法2:树形dp,枚举根节点,找最大和次大子树
无论边权正负均可

点击查看代码
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10, INF = 0x3f3f3f3f;
struct T {
    int v, w, nx;
} g[N];
int h[N], idx, ans;
void add(int u, int v, int w) {
    g[++idx] = {v, w, h[u]}, h[u] = idx;
}
int dfs(int u, int fu) {
    int dist = 0, d1 = 0, d2 = 0;// d1,d2: 最大,次大
    for (int i = h[u]; i; i = g[i].nx) {
        int v = g[i].v, w = g[i].w;
        if (fu == v) continue;
        int d = dfs(v, u) + w;
        dist = max(dist, d);
        if (d >= d1) d2 = d1, d1 = d;
        else if (d > d2) d2 = d;
    }
    ans = max(ans, d1 + d2);
    return dist;
}
int main() {
    int x, y, z;
    while (cin >> x >> y >> z) {
        add(x, y, z), add(y, x, z);
    }
    dfs(1, -1);
    cout << ans;
    return 0;
}

标签:North,idx,int,2631,dfs,add,POJ,d2,d1
From: https://www.cnblogs.com/hellohebin/p/17714479.html

相关文章

  • 【POJ 2488】A Knight‘s Journey 题解(深度优先搜索)
    背景骑士厌倦了一次又一次地看到同样的黑白方块,决定去旅行全世界每当骑士移动时,它是一个方向上的两个正方形和一个垂直于这个方向的正方形。骑士的世界就是他生活的棋盘。我们的骑士生活在一个棋盘上,这个棋盘的面积比普通的8*8棋盘小,但它仍然是矩形的。你能帮助这位冒险的骑士制......
  • 【POJ 3275】Ranking the Cows 题解(传递闭包)
    农夫约翰的N头奶牛(1≤N≤1000)产奶率各不相同,FJ希望根据这些比率从最快的奶牛到最慢的奶牛订购奶牛。FJ已经比较了M(1≤M≤10000)对奶牛的产奶率。他想列出另外C对奶牛的列表,这样,如果他现在比较这些C对奶牛,他肯定能够推断出所有N头牛的正确顺序。请帮助他确定C的最小值,这样的列表是可......
  • 【2023潇湘夜雨】WIN11_Pro_23H2.22631.2338软件选装纯净版9.16
    【系统简介】=============================================================1.本次更新母盘来自WIN11_Pro_23H2.22631.2338。2.增加部分优化方案,手工精简部分较多。3.OS版本号为22631.2338。精简系统只是为部分用户安装,个别要求高的去MSDN下。4.集成《DrvCeo-2.13.0.8》网卡版、......
  • POJ 2935 Basic Wall Maze BFS
    注意墙的处理,我是这么做的,把每个方块不能行走的方向标记出来,剩他的就是传统BFS了。#include<stdio.h>#include<queue>usingnamespacestd;intsx,sy,ex,ey;inth[4]={1,-1,0,0};intg[4]={0,0,1,-1};intdir[8][8][5];boolvisit[7][7];structpoint{ intx; inty; in......
  • poj 2528 Mayor's posters 线段树+离散化
    离散化处理要注意+1(看了HH大牛的博客懂的,以前自己的代码是不对的)例如数据:1311013610这样,普通离散化处理 {13610},然后此程序会操作成点染色,于是结果为2,但正确答案为3;HH大牛给出一种离散化方法:     如果相邻数字间距大于1的话,在其中加上任意一个数字,比如加......
  • POJ 2823 Sliding Window 单调队列
    这道题就是用单调队列来维护,但是用G++交TLE,用c++5000多ms,真是囧...代码很丑,就凑合着看吧#include<stdio.h>inta[1000009],que[1000009];intmain(){ intn,k,i,head,tail,flag=1,f; scanf("%d%d",&n,&k); for(i=1;i<=n;i++) scanf("%d",&a[i]); head=......
  • POJ 2057 The Lost House 树形DP+贪心
          最近一直在做树形dp,感觉这道题出的非常不错。卡了我一天。。      一上来读完题感觉和dp的思路很像,但是自己太弱了,无从下手。于是各种百度看结题报告、看论文。推荐几个结题报告 http://blog.sina.com.cn/s/blog_5f5353cc0100hd08.html还有06年国家集训队杨......
  • poj 1182 食物链---带权值的并查集
    这题就一组数据,用while(scnaf(“%d%d”,&n,&m)!=EOF)..就wa了,我wa了数次,无语了。。带权值的并查集,d[]数组存的是每个点和根节点的关系,同类为d[i]=0; 根节点吃i点为d[i]=1; i点吃根节点为d[i]=2;自己画图感受一下吧!!#include<stdio.h>#include<string.h>#include<stdlib.h>in......
  • POJ 2186-Popular Cows ---强连通分量
    本题让求有多少点 是图中所有点都可到达改点的定理:在一个有向图中,如果有一个节点的出度为0,并且仅有一个这样的点,则该图中所有的点都可到达该点先求出图的强连通分量,然后将每个强连通分量化为一个层次,求是否存在一个强连通分量,该分量的出度为一,并且仅有一个这样的分量,则该连通分量......
  • POJ 2299 Ultra-QuickSort ---归并排序 求逆序
    归并排序的模板。能求逆序。。。。#include<stdio.h>#include<string.h>intn;longlonga[500005],b[500005];longlongsum;voidmerge(intl,intm,intr){ inti=l,j=m+1,k=0; while(i<=m&&j<=r) { if(a[i]<=a[j]) b[k++]=a[i++]; else......