1. 程式人生 > 其它 >求樹的直徑兩種方法/樹形dp學習

求樹的直徑兩種方法/樹形dp學習

失蹤了幾個月 我再次回來學習演算法了。感覺有點來不及了QAQ

希望自己繼續努力吧 加油少年!相信自己 擁有無限可能!!!

兩種方法求樹的直徑

何為樹的直徑?直徑既是數值概念,又指的是路徑,一般初學我們要學習的是求如何求直徑的長度

怎麼樣去求一棵樹的直徑呢?

  1. 任取一個點作為起點,找到距離該點距離最大的一個點u
  2. 再找到距離u最遠的點v
  3. 則u與v間的路徑就是一條直徑

為什麼這個做法是正確的呢?

事實上 我們只要證明u一定是某條直徑的一個端點,那麼很顯然就可以說明u與v之間的路徑是一條直徑

證明過程

假設已知BC為直徑(當然畫的不太像原諒我

u是距離A最遠的點

情況一:直徑與au不相交(注在這份圖中D點就是u

顯然① ≥ ② + ③;

所以① +②≥③

此時u即為直徑的端點

情況二:直徑與au相交

由定義可知②≥① 顯然u也是直徑的端點

綜上,uv一定是直徑得證。

對於樹的直徑 有兩種做法 一種是搜尋(深搜廣搜其實更推薦bfs)還有就是dp

兩次dfs求直徑

dfs就是按照上面的做法直接做就好了

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 10010, M = N * 2, INF = 0x3f3f3f3f
; int n,m; int h[N], e[M], w[M], ne[M], idx,ans; int d[N]; void add(int a, int b, int c) { e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ; } void dfs(int u, int father) { if(d[u] > ans) { ans = d[u]; m = u; } for (int i = h[u]; i != -1; i = ne[i]) {
int j = e[i]; if (j == father) continue; d[j] = d[u] + w[i]; dfs(j,u); } return ; } int main() { cin >> n; memset(h, -1, sizeof h); for (int i = 0; i < n - 1; i ++ ) { int a, b, c; cin >> a >> b >> c; add(a, b, c), add(b, a, c); } dfs(1,-1); ans = 0; d[m] = 0; dfs(m,-1); printf("%d\n", ans); return 0; }

樹形dp求直徑

把所有直徑(路徑概念)都算一下,找個最大值

直徑直接列舉太複雜,不如列舉點,看作是一個點把直徑提起來,那麼我只要算兩邊的長度就好了。

找到一個最大路徑和次大路徑 所構成的就是最長路徑

#include <iostream>
#include <cstring>
#include <algorithm>


using namespace std;

const int N = 100010;
const int M = N << 1;

int h[N],ne[M],e[M],w[M],idx,ans;

int n;

inline void add(int a,int b,int c)
{
    e[idx] = b,ne[idx] = h[a],w[idx] = c,h[a] = idx ++;
}


int dfs(int u,int father)
{
    int d1 = 0,d2 = 0;
    for(int i = h[u];i != -1;i = ne[i])
    {
        int j = e[i];
        if(j == father) continue;
        int dist = dfs(j,u) + w[i];
        if(dist > d1)
        {
            d2 = d1,d1 = dist;
        }
        else if(dist > d2)
        {
            d2 = dist;
        }
    }
    
    ans = max(ans,d1 + d2);
    return d1;
}

signed main()
{
    memset(h,-1,sizeof h);
    cin >> n;
    for(int i = 1; i < n; ++ i)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);
        add(b,a,c);
    }
    
    dfs(1,-1);
    cout << ans << endl;
    return 0;
}