大意就是把一棵树的点染成m种颜色,其中1号点的颜色必须染恰好k个节点。
总代价是所有两端点颜色相同的边的边权。
求最小代价。
解:可以分为m == 2和m > 2两个题。
m > 2时有代价的边的两端点显然是一号点色的(设为白色)。
m == 2的时候还要计算两端点是另外一种颜色的边的贡献(黑色)。
状态设计就是f[x][j][0/1]表示x为根的子树中染了j个白色点,x号点染/不染的最小代价。
转移的时候做一个类似树上背包的转移即可。
注意m == 2的时候,更新f[i][j][0]合并子树的时候要把原来的那个值覆盖掉,因为子节点也是0的时候会有代价,所以不能保留原来的没有计算这个代价的值。
我比较菜,一开始没发现要分成两个题,就写了两个DFS函数...
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 5 const int N = 310; 6 7 struct Edge { 8 int nex, v, len; 9 }edge[N << 1]; int top; 10 11 int f[N][N][2], e[N], n, k; 12 13 inline void add(int x, int y, int z) { 14 top++; 15 edge[top].v = y; 16 edge[top].len = z; 17 edge[top].nex = e[x]; 18 e[x] = top; 19 return; 20 } 21 22 void DFS_2(int x, int fa) { 23 f[x][0][0] = 0; 24 f[x][1][1] = 0; 25 for(int i = e[x]; i; i = edge[i].nex) { 26 int y = edge[i].v; 27 if(y == fa) { 28 continue; 29 } 30 DFS_2(y, x); 31 for(int j = k; j >= 0; j--) { 32 /// f[x][j] [0/1] 33 int t = 0x3f3f3f3f; 34 for(int p = j; p >= 0; p--) { 35 t = std::min(t, std::min(f[y][p][1] + f[x][j - p][0], f[y][p][0] + f[x][j - p][0] + edge[i].len)); 36 } 37 f[x][j][0] = t; 38 t = 0x3f3f3f3f; 39 for(int p = j; p >= 0; p--) { 40 t = std::min(t, std::min(f[y][p][1] + f[x][j - p][1] + edge[i].len, f[y][p][0] + f[x][j - p][1])); 41 } 42 f[x][j][1] = t; 43 /*for(int p = j; p >= 0; p--) { 44 f[x][j][0] = std::min(f[x][j][0], f[y][p][0] + f[x][j - p][0] + edge[i].len); 45 f[x][j][0] = std::min(f[x][j][0], f[y][p][1] + f[x][j - p][0]); 46 if(j != p) { 47 if(x == 1 && j == 2)printf("step 0 f[1][2][1] = %d ", f[1][2][1]); 48 f[x][j][1] = std::min(f[x][j][1], f[y][p][0] + f[x][j - p][1]); 49 if(x == 1 && j == 2)printf("step 1 f[1][2][1] = %d ", f[1][2][1]); 50 f[x][j][1] = std::min(f[x][j][1], f[y][p][1] + f[x][j - p][1] + edge[i].len); 51 if(x == 1 && j == 2)printf("step 2 f[1][2][1] = %d ", f[1][2][1]); 52 if(x == 1 && j == 4 && y == 2 && p == 2) { 53 printf("%d + %d ", f[y][p][0] + f[x][j - p][1]); 54 } 55 if(x == 1 && j == 2) { 56 printf("> f 1 2 1 = %d p = %d ", f[1][2][1], p); 57 printf("> %d + %d ", f[y][p][0], f[x][j - p][1]); 58 printf("> %d + %d ", f[y][p][1], f[x][j - p][1] + edge[i].len); 59 } 60 } 61 }*/ 62 } 63 } 64 /*for(int j = 0; j <= k; j++) { 65 printf("f %d %d %d = %d ", x, j, 0, f[x][j][0]); 66 */ 67 return; 68 } 69 70 void DFS_1(int x, int fa) { 71 f[x][0][0] = 0; 72 f[x][1][1] = 0; 73 for(int i = e[x]; i; i = edge[i].nex) { 74 int y = edge[i].v; 75 if(y == fa) { 76 continue; 77 } 78 DFS_1(y, x); 79 // 80 for(int j = k; j >= 1; j--) { 81 /// f[x][j] [0/1] 82 for(int p = j; p >= 1; p--) { 83 f[x][j][0] = std::min(f[x][j][0], f[y][p][0] + f[x][j - p][0]); 84 f[x][j][0] = std::min(f[x][j][0], f[y][p][1] + f[x][j - p][0]); 85 if(p != j) { 86 f[x][j][1] = std::min(f[x][j][1], f[y][p][0] + f[x][j - p][1]); 87 f[x][j][1] = std::min(f[x][j][1], f[y][p][1] + f[x][j - p][1] + edge[i].len); 88 } 89 } 90 } 91 } 92 return; 93 } 94 95 int main() { 96 int m; 97 memset(f, 0x3f, sizeof(f)); 98 scanf("%d%d%d", &n, &m, &k); 99 for(int i = 1, x, y, z; i < n; i++) { 100 scanf("%d%d%d", &x, &y, &z); 101 add(x, y, z); 102 add(y, x, z); 103 } 104 if(n - k < m - 1) { 105 puts("-1"); 106 return 0; 107 } 108 if(m > 2) { 109 DFS_1(1, 0); 110 printf("%d ", f[1][k][1]); 111 } 112 else { 113 DFS_2(1, 0); 114 printf("%d ", f[1][k][1]); 115 } 116 return 0; 117 }