CodeForces - 14D Two Paths(兩次bfs求樹的直徑)
阿新 • • 發佈:2020-10-11
題目大意:
給定一棵權值為\(1\)的樹,從中兩條最長的路徑且兩者沒有公共節點,求最大的二路徑乘積。
思路:
觀察到\(n\)的範圍很小,可以列舉每條要刪的邊,再在兩個子樹中求樹的直徑,相乘即為答案。
本題我採用兩次\(bfs\)的方式求樹的直徑。
另外,記得打上刪除標記。
時間複雜度\(O(n^2)\)。
Code:
#include <bits/stdc++.h> using namespace std; const int N = 224; //maxv:源點能到的最遠點,maxdis:最遠點對應的距離, struct Edge { int from, to, next, w; bool tag; }edges[N << 1]; int head[N], maxdis,maxv, ne; void init(){ memset(head, -1, sizeof(head)); maxv = maxdis = ne = 0; } void add(int u, int v, int w) { edges[ne] = { u, v, head[u], w, true }; head[u] = ne++; } //u:dfs的源點,f: u點的父節點,d2s:u點到源點的距離 void dfs(int u, int f, int d2s) { if (maxdis < d2s){ maxdis = d2s; maxv = u; } for (int e = head[u]; e != -1; e = edges[e].next) { int v = edges[e].to, w = edges[e].w; if (!edges[e].tag) continue; if (v == f) continue; //父節點已經訪問過,防止重複遍歷,相反孩子不會重複遍歷。 dfs(v, u, d2s + w); } } int main() { int ans = 0; int n; cin >> n; memset(head, -1, sizeof(head)); for (int i = 1; i < n; i++) { int u, v, w = 1; cin >> u >> v; add(u, v, w), add(v, u, w); } for (int i = 0; i < ne; i += 2) { edges[i].tag = edges[i^1].tag = 0; //雙向邊都堵住 int u = edges[i].from, v = edges[i].to; dfs(u, -1, 0); //從結點u開始遍歷,找到最遠點maxv及對應的最遠距離maxdis maxdis = 0; dfs(maxv, -1, 0);//從結點maxv開始遍歷,找到最遠點對應的距離maxdis int mul1 = maxdis; maxv = maxdis = 0; dfs(v, -1, 0); maxdis = 0; dfs(maxv, -1, 0); int mul2 = maxdis; maxv = maxdis = 0; ans = max(ans, mul1 * mul2); edges[i].tag = edges[i^1].tag = 1; } cout << ans << endl; return 0; }