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\n", r); 86 } 87 }