大意就是把一棵樹的點染成m種顏色,其中1號點的顏色必須染剛好k個節點。ide
總代價是全部兩端點顏色相同的邊的邊權。函數
求最小代價。spa
解:能夠分爲m == 2和m > 2兩個題。設計
m > 2時有代價的邊的兩端點顯然是一號點色的(設爲白色)。code
m == 2的時候還要計算兩端點是另一種顏色的邊的貢獻(黑色)。blog
狀態設計就是f[x][j][0/1]表示x爲根的子樹中染了j個白色點,x號點染/不染的最小代價。string
轉移的時候作一個相似樹上揹包的轉移便可。it
注意m == 2的時候,更新f[i][j][0]合併子樹的時候要把原來的那個值覆蓋掉,由於子節點也是0的時候會有代價,因此不能保留原來的沒有計算這個代價的值。io
我比較菜,一開始沒發現要分紅兩個題,就寫了兩個DFS函數...event
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 \n", 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 \n", 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 \n", f[1][2][1]); 52 if(x == 1 && j == 4 && y == 2 && p == 2) { 53 printf("%d + %d \n", 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 \n", f[1][2][1], p); 57 printf("> %d + %d \n", f[y][p][0], f[x][j - p][1]); 58 printf("> %d + %d \n", 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 \n", 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\n", f[1][k][1]); 111 } 112 else { 113 DFS_2(1, 0); 114 printf("%d\n", f[1][k][1]); 115 } 116 return 0; 117 }