洛谷P4362 贪吃的九头龙

大意就是把一棵树的点染成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 \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 }
AC代码

 

posted @ 2019-01-27 18:39  huyufeifei  阅读(196)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

ReadEra 阅读书籍

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜