hdu6769 In Search of Gold

题目描述:

给定一个颗树,每一条边有俩个权值w1和w2。选择k条边权为w1的边,其余都是w2。让直径最小。

题解:

树形dp,f[u][k]表示以u为根结点的子树的最小直径,因为直接求不好求,可以二分判可行性,求出答案。考虑转移,类似背包。

 if(f[u][k] + f[j][z] + A <= mid) tmp[k + z + 1] = min(tmp[k + z + 1], max(f[u][k], f[j][z] + A));

 if(f[u][k] + f[j][z] + B <= mid) tmp[k + z] = min(tmp[k + z], max(f[u][k], f[j][z] + B));

 

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 2e4 + 10;
 5 const int M = 4e4 + 10;
 6 typedef long long ll;
 7 inline int read()
 8 {
 9     char ch = getchar();int x = 0, f = 1;
10     while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
11     while(ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) - '0' + ch; ch = getchar();}
12     return x * f;
13 }
14 
15 ll f[N][21];
16 ll tmp[21];
17 int n, m, t;
18 int size[N];
19 int h[N], e[M], ne[M], idx, w1[M], w2[M];
20 
21 
22 void init()
23 {
24     idx = 0;
25     for (int i = 1; i <= n; i ++) h[i] = -1;
26 }
27 
28 void add(int a, int b, int c, int d)
29 {
30     w1[idx] = c;
31     w2[idx] = d;
32     e[idx] = b;
33     ne[idx] = h[a];
34     h[a] = idx ++;
35 }
36 
37 void dfs(int u, int fa, ll mid)
38 {
39     size[u] = f[u][0] = 0;
40     for (int i = h[u]; ~i; i = ne[i])
41     {
42         int j = e[i];
43         if(j == fa) continue;
44         dfs(j, u, mid);
45         ll A = w1[i], B = w2[i];
46        // size[u] += size[j];
47         int pre = size[u], cur = size[j];
48         int now = min(pre + cur + 1, m);
49         for (int k = 0; k <= now; k ++)
50             tmp[k] = mid + 1;
51         for (int k = 0; k <= pre; k ++)
52         {
53             for (int z = 0; z + k <= now && z <= cur; z ++)
54             {
55                 if(f[u][k] + f[j][z] + A <= mid) tmp[k + z + 1] = min(tmp[k + z + 1], max(f[u][k], f[j][z] + A));
56                 if(f[u][k] + f[j][z] + B <= mid) tmp[k + z] = min(tmp[k + z], max(f[u][k], f[j][z] + B));
57             }
58         }
59         size[u] = now;
60         for (int j = 0; j <= now; j ++) f[u][j] = tmp[j];
61     }
62 }
63 
64 int main()
65 {
66     t = read();
67     while(t --)
68     {
69         n = read(), m = read();
70         init();
71         ll l = 0, r = 0;
72         for (int i = 1; i <= n - 1; i ++)
73         {
74             int a = read(), b = read(), x = read(), y = read();
75             add(a, b, x, y); add(b, a, x, y);
76             r += max(x, y);
77         }
78         while(l < r)
79         {
80             ll mid = l + r >> 1;
81             dfs(1, 0, mid);
82             if(f[1][m] <= mid) r = mid;
83             else l = mid + 1;
84         }
85         printf("%lld
", r);
86     }
87 }
View Code
原文地址:https://www.cnblogs.com/xwdzuishuai/p/14083696.html