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;
}
上一篇:[CF545E] Paths and Trees - 最短路


下一篇:PAT 1155 Heap Paths