#P1782. 2024.03.31-第3题-树的期望
-
1000ms
Tried: 61
Accepted: 18
Difficulty: 6
所属公司 :
字节
时间 :2024年3月31日
-
算法标签>DFS
2024.03.31-第3题-树的期望
思路
DFS 每个点 u ,当删除点 u 时,形成若干个子树 v1, v2, v3, 以及一个 u 的祖先连通块
v1,v2 和 v3 等子树的大小可以通过 DFS 获得,u 的祖先连通块大小为 n - 1 - (v1 + v2 + v3 + ...)
取所有子树以及 u 的祖先连通块大小的最大值即可
最终对于每个点删除后的最大连通块的大小累加,最后除以 n 即为期望。
时间复杂度:O(n)
代码
C++
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
vector<int> g[N];
int n;
long long ans = 0;
int dfs(int u, int fa) {
int res = 0;
int sum = 0;
for (int v: g[u]) {
if (v == fa) continue;
int c = dfs(v, u);
res = max(res, c);
sum += c;
}
res = max(res, n - 1 - sum);
ans += res;
return sum + 1;
}
int main()
{
scanf("%d", &n);
for (int i = 1; i < n; ++i) {
int u, v;
scanf("%d%d", &u, &v);
g[u].emplace_back(v);
g[v].emplace_back(u);
}
dfs(1, 0);
printf("%.10lf\n", 1.0 * ans / n);
return 0;
}
java
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
static List<List<Integer>> tree = new ArrayList<>();
static long res = 0;
static int[] visited;
static int n;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
for (int i = 0; i < n + 1; i++) {tree.add(new ArrayList<>());}
for (int i = 0; i < n - 1; i++) {
int u = sc.nextInt();int v = sc.nextInt();
tree.get(u).add(v); tree.get(v).add(u);}
visited = new int[n+1];
DFS(1);
System.out.println(res/(double)n);
}
private static int DFS(int i) {
int sum=0,max=0;
visited[i]=1;
for(int son:tree.get(i)){
if(visited[son]==0){
int sonNode = DFS(son);
sum+=sonNode;
max = Math.max(max,sonNode);
}
}
res+=Math.max(max,n-sum-1);
return sum+1;
}
}
python
n = int(input())
edges = []
for i in range(n - 1):
edges.append(list(map(int, input().split())))
#print(edges)
from collections import *
ma = defaultdict(list)
for u,v in edges:
ma[u].append(v)
ma[v].append(u)
ans = 0
def dfs(u, fa):
global ans
res = 0
_sum = 0
for v in ma[u]:
if v == fa:
continue
c = dfs(v, u)
res = max(res, c)
_sum += c
res = max(res, n - 1 - _sum)
ans += res
#print(ans, res)
return _sum + 1
if n == 1:
print("0.00000005")
exit(0)
dfs(1, 0)
print("{:.10f}".format(ans / n))
题目描述
众所周知,点分治算法最重要的一个步骤是寻找一棵树的重心后删除,满足形成的森林中最大连通块尽可能小。 但很可惜,小红不会寻找树的重心,因此她会随机选择一个节点进行删除。这样就会导致最终算法的复杂度增加。小红想知道,对于一个给定的树,随机取一个点删除,形成的森林中最大连通块大小的期望是多少?
输入描述
第一行输入一个正整数n,代表树的节点数量 接下来的n−1行,每行输入两个正整数u,v,代表节点u和节点v有一条边连接。
1≤n≤105
1≤u,v≤n
输出描述
一个浮点数,代表最终最大连通块的大小期望。如果你的答案和标准答案的相对误差小于10−6,则认为你的答案正确。
样例1
输入
2
1 2
输出
1.000000000
说明
无论删除的是哪个节点,形成的森林的最大连通块大小均是 1.
样例2
输入
3
1 3
2 3
输出
1.6666666666667
说明
删除1号节点时,最大连通块大小为2。
删除2号节点时,最大连通块大小为1。
删除3号节点时,最大连通块大小为2。
因此随机选一个节点删除,连通块的大小期望是5/3