【題意】:
給定一棵樹,給定邊權的區間[0,L],求最終樹的最長路<=S的概率; 【題解】:武大校賽的樹dp,放了好久,看著題解勉強過了。只可以說我的樹dp太水了,還停留在背包的階段。
設狀態dp[i][j]表示以i為根的子樹,其葉子結點到i的最長距離為j且該子樹最長路徑不超過s的概率。
對于u的一個子樹v,先枚舉u連v的長度,然后再把之前的子樹和v這條鏈合并,好復雜,不會表達了,直接研究代碼吧。
【代碼】:
1 #include "iostream"
2 #include "cstdio"
3 #include "cstring"
4 #include "algorithm"
5 #include "vector"
6 #include "queue"
7 #include "cmath"
8 #include "string"
9 #include "cctype"
10 #include "map"
11 #include "iomanip"
12 using namespace std;
13 #define pb push_back
14 #define mp make_pair
15 #define fi first
16 #define se second
17 #define lc(x) (x << 1)
18 #define rc(x) (x << 1 | 1)
19 #define lowbit(x) (x & (-x))
20 #define ll long long
21 #define maxn 70
22 #define maxs 530
23 int n, l, s;
24 double dp[maxn][maxs];
25 double son[maxs], tmp[maxs];
26 double e;
27 vector<int> vec[maxn];
28 void dfs(int u, int fa) {
29 memset(dp[u], 0, sizeof(dp[u]));
30 dp[u][0] = 1.0;
31 int size = vec[u].size();
32 for(int i = 0; i < size; i++) {
33 int v = vec[u][i];
34 if(v == fa) continue;
35 dfs(v, u);
36 memset(son, 0, sizeof(son));
37 memset(tmp, 0, sizeof(tmp));
38 for(int j = 0; j <= l; j++)
39 for(int k = 0; k <= s; k++)
40 if(j + k <= s)
41 son[j+k] += e * dp[v][k];
42 for(int j = 0; j <= s; j++)
43 for(int k = 0; k <= s - j; k++)
44 tmp[max(j, k)] += son[j] * dp[u][k];
45 for(int j = 0; j <= s; j++)
46 dp[u][j] = tmp[j];
47 }
48 }
49
50 int main() {
51 int T, Case = 1;
52 scanf("%d", &T);
53 while(T--) {
54 scanf("%d%d%d", &n, &l, &s);
55 for(int i = 0; i <= n; i++) vec[i].clear();
56 e = 1.0 / (1.0 + l);
57 for(int i = 1; i < n; i++) {
58 int a, b;
59 scanf("%d%d", &a, &b);
60 vec[a].pb(b);
61 vec[b].pb(a);
62 }
63 dfs(1, -1);
64 double ans = 0.0;
65 for(int i = 0; i <= s; i++) ans += dp[1][i];
66 printf("Case %d: %.6f\n", Case++, ans);
67 }
68 return 0;
69 }
70