1. 程式人生 > 實用技巧 >POJ 1985.Cow Marathon(DFS求樹的直徑模板題)

POJ 1985.Cow Marathon(DFS求樹的直徑模板題)

兩次BFS/DFS求樹的直徑

我們可以先從任意一點開始DFS,記錄下當前點所能到達的最遠距離,這個點為P。

在從P開始DFS記錄下所能達到的最遠點的距離,這個點為Q。

\(P , Q\)就是直徑的端點,\(d i s ( P , Q )\)就是直徑。
具體程式碼見下題

題意:有N個農田以及M條路,給出M條路的長度以及路的方向(這道題不影響,用不到),讓你找到一條 兩農田(任意的)間的路徑,使得距離最長,並輸出最長距離。
這裡用dfs求直徑,當然也可以用bfs和樹形DP來做。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define over(i,s,t) for(register int i = s;i <= t;++i)
#define lver(i,t,s) for(register int i = t;i >= s;--i)
using namespace std;
const int N = 5e5 + 7;
const int M = 2007;

int head[N], ver[N], tot, edge[N], nex[N];
int n, m, ans;
int dis[N], vis[N];

inline void add(int u, int v, int w) {
    ver[++tot] = v;
    edge[tot] = w;
    nex[tot] = head[u];
    head[u] = tot;
}

//兩次dfs一次求P一次求Q
void dfs(int u, int& ed) {
    if (dis[u] > ans)ans = dis[u], ed = u;
    vis[u] = 1;
    for (int i = head[u]; ~i; i = nex[i]) {
        int v = ver[i], w = edge[i];
        if (vis[v])continue;
        dis[v] = dis[u] + w;
        dfs(v, ed);
    }
    return;
}

int p, q;
void solve() {
    dfs(1, p);//第一遍DFS求當下點能達到的最大距離
    ans = dis[p] = 0;
    memset(vis, 0, sizeof vis);
    dfs(p, q);//第二遍DFS求從p開始能達到的最遠距離
    //p,q的距離就是最大距離了,即 ans
    cout << ans << endl;
}
int main()
{
    while (scanf("%d%d", &n, &m) != EOF) {
        memset(head, -1, sizeof head);
        memset(vis, 0, sizeof vis);
        memset(dis, 0, sizeof dis);
        tot = 0;
        over(i, 1, m) {
            int u, v, w;
            char ch[2];
            scanf("%d%d%d%s", &u, &v, &w, ch);
            add(u, v, w);
            add(v, u, w);
        }
        solve();
    }
    return 0;
}