zoukankan      html  css  js  c++  java
  • 洛谷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 
    ", 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 }
    AC代码
  • 相关阅读:
    Springboot使用外置tomcat的同时使用websocket通信遇到的坑
    SpringBoot 使用 ApplicationContextAware实现类出现NullPointException的问题
    Java搭建微信公众号的服务器配置
    axios异步访问后台 @RequestParam 获取参数 HTTP Status 400
    springboot启动失败的问题('hibernate.dialect' not set)
    Java Optional 类
    ubuntu 18.04 解决无法联网的问题
    ubuntu安装rpm格式文件方法
    简述vue中父子组件是怎样相互传递值的(基础向)
    实现网站中英文切换的三种方法
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10327592.html
Copyright © 2011-2022 走看看