题目大意:
给定一棵权值为\(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;
}