1. 程式人生 > 實用技巧 >CodeForces - 14D Two Paths(兩次bfs求樹的直徑)

CodeForces - 14D Two Paths(兩次bfs求樹的直徑)

CF14D Two Paths

題目大意:

給定一棵權值為\(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;
}