大意就是把一棵树的点染成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函数...

 #include <cstdio>
#include <algorithm>
#include <cstring> const int N = ; struct Edge {
int nex, v, len;
}edge[N << ]; int top; int f[N][N][], e[N], n, k; inline void add(int x, int y, int z) {
top++;
edge[top].v = y;
edge[top].len = z;
edge[top].nex = e[x];
e[x] = top;
return;
} void DFS_2(int x, int fa) {
f[x][][] = ;
f[x][][] = ;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == fa) {
continue;
}
DFS_2(y, x);
for(int j = k; j >= ; j--) {
/// f[x][j] [0/1]
int t = 0x3f3f3f3f;
for(int p = j; p >= ; p--) {
t = std::min(t, std::min(f[y][p][] + f[x][j - p][], f[y][p][] + f[x][j - p][] + edge[i].len));
}
f[x][j][] = t;
t = 0x3f3f3f3f;
for(int p = j; p >= ; p--) {
t = std::min(t, std::min(f[y][p][] + f[x][j - p][] + edge[i].len, f[y][p][] + f[x][j - p][]));
}
f[x][j][] = t;
/*for(int p = j; p >= 0; p--) {
f[x][j][0] = std::min(f[x][j][0], f[y][p][0] + f[x][j - p][0] + edge[i].len);
f[x][j][0] = std::min(f[x][j][0], f[y][p][1] + f[x][j - p][0]);
if(j != p) {
if(x == 1 && j == 2)printf("step 0 f[1][2][1] = %d \n", f[1][2][1]);
f[x][j][1] = std::min(f[x][j][1], f[y][p][0] + f[x][j - p][1]);
if(x == 1 && j == 2)printf("step 1 f[1][2][1] = %d \n", f[1][2][1]);
f[x][j][1] = std::min(f[x][j][1], f[y][p][1] + f[x][j - p][1] + edge[i].len);
if(x == 1 && j == 2)printf("step 2 f[1][2][1] = %d \n", f[1][2][1]);
if(x == 1 && j == 4 && y == 2 && p == 2) {
printf("%d + %d \n", f[y][p][0] + f[x][j - p][1]);
}
if(x == 1 && j == 2) {
printf("> f 1 2 1 = %d p = %d \n", f[1][2][1], p);
printf("> %d + %d \n", f[y][p][0], f[x][j - p][1]);
printf("> %d + %d \n", f[y][p][1], f[x][j - p][1] + edge[i].len);
}
}
}*/
}
}
/*for(int j = 0; j <= k; j++) {
printf("f %d %d %d = %d \n", x, j, 0, f[x][j][0]);
*/
return;
} void DFS_1(int x, int fa) {
f[x][][] = ;
f[x][][] = ;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == fa) {
continue;
}
DFS_1(y, x);
//
for(int j = k; j >= ; j--) {
/// f[x][j] [0/1]
for(int p = j; p >= ; p--) {
f[x][j][] = std::min(f[x][j][], f[y][p][] + f[x][j - p][]);
f[x][j][] = std::min(f[x][j][], f[y][p][] + f[x][j - p][]);
if(p != j) {
f[x][j][] = std::min(f[x][j][], f[y][p][] + f[x][j - p][]);
f[x][j][] = std::min(f[x][j][], f[y][p][] + f[x][j - p][] + edge[i].len);
}
}
}
}
return;
} int main() {
int m;
memset(f, 0x3f, sizeof(f));
scanf("%d%d%d", &n, &m, &k);
for(int i = , x, y, z; i < n; i++) {
scanf("%d%d%d", &x, &y, &z);
add(x, y, z);
add(y, x, z);
}
if(n - k < m - ) {
puts("-1");
return ;
}
if(m > ) {
DFS_1(, );
printf("%d\n", f[][k][]);
}
else {
DFS_2(, );
printf("%d\n", f[][k][]);
}
return ;
}

AC代码

洛谷P4362 贪吃的九头龙的更多相关文章

  1. Vijos1523贪吃的九头龙【树形DP】

    贪吃的九头龙 传说中的九头龙是一种特别贪吃的动物.虽然名字叫"九头龙",但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头 ...

  2. [codevs1746][NOI2002]贪吃的九头龙

    [codevs1746][NOI2002]贪吃的九头龙 试题描述 传说中的九头龙是一种特别贪吃的动物.虽然名字叫"九头龙",但这只是说它出生的时候有九个头,而在成长的过程中,它有时 ...

  3. 贪吃的九头龙(tyvj P1523)

    T2 .tyvj   P1523贪吃的九头龙 描述 传说中的九头龙是一种特别贪吃的动物.虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于 ...

  4. Vijos 1523 贪吃的九头龙 【树形DP】

    贪吃的九头龙 背景 安徽省芜湖市第二十七中学测试题 NOI 2002 贪吃的九头龙(dragon) Description:OfficialData:OfficialProgram:Converted ...

  5. [NOI2002]贪吃的九头龙(树形dp)

    [NOI2002]贪吃的九头龙 题目背景 传说中的九头龙是一种特别贪吃的动物.虽然名字叫"九头龙",但这只是 说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的 ...

  6. codevs1746 贪吃的九头龙

    [问题描述]传说中的九头龙是一种特别贪吃的动物.虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落.有一 ...

  7. vojis1523 NOI2002 贪吃的九头龙

    描述 传说中的九头龙是一种特别贪吃的动物.虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落. 有一天, ...

  8. codevs贪吃的九头龙

    传说中的九头龙是一种特别贪吃的动物.虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落.有一天,有M 个 ...

  9. [NOI2002] 贪吃的九头龙

    题目类型:树形DP 传送门:>Here< 题意:有一只九头龙要吃了一颗树,给出一棵\(N\)个节点的带边权的树.九头龙有\(M\)个头,其中一个是大头,大头要吃恰好\(K\)个节点,其他头 ...

随机推荐

  1. k8s授权访问

    #监听本地的8080端口 kubectl  proxy --port=8080 [root@k8s-m ~]# kubectl proxy --port=8080Starting to serve o ...

  2. 注解方式过滤器(Filter)不能过滤Servlet的问题

    https://www.aliyun.com/jiaocheng/778495.html 今天写filter(过滤器)的时候,碰到一个奇怪的问题,发现filter可以过滤urlPatterns,但是无 ...

  3. oracle判断是否包含字符串的方法

    首先想到的就是contains,contains用法如下: select * from students where contains(address,  ‘beijing’) 但是,使用contai ...

  4. vs + babelua + cocos2d-x

    https://blog.csdn.net/dugaoda/article/details/60467037 https://blog.csdn.net/taotanty/article/detail ...

  5. Java自定义线程池-记录每个线程执行耗时

    ThreadPoolExecutor是可扩展的,其提供了几个可在子类化中改写的方法,如下: protected void beforeExecute(Thread t, Runnable r) { } ...

  6. BZOJ2565最长双回文串——manacher

    题目描述 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为“abc”,逆序为“cba”,不相同).输入长度为n的串S,求S的最长双回文子串T,即可将T分为两 ...

  7. Elasticsearch 中数据类型 text 与 keyword 的区别

    随着ElasticSearch 5.X 系列的到来, 同时也迎来了该版本的重大特性之一: 移除了string类型. 这个变动的根本原因是string类型会给我们带来很多困惑: 因为ElasticSea ...

  8. 安卓Android基础—第一天

    1.1G-4G的介绍 1G 大哥大 2G 小灵通 采用gsm标准(美国军方标准民用化) 发短信 3G 沃 72M/s 4G lte 100M/s 5G 华为 10G/s 小公司卖茶品大公司卖版权(标准 ...

  9. groovy的效率问题

    刚开始学groovy,知道了它会先变异成class 文件,然后再用jvm 执行.写了Hello World程序,查看它的编译文件,发现groovy的效率挺低的.不但编译文件的代码多,而且需要依赖很多g ...

  10. 爬虫_拉勾网(selenium)

    使用selenium进行翻页获取职位链接,再对链接进行解析 会爬取到部分空列表,感觉是网速太慢了,加了time.sleep()还是会有空列表 from selenium import webdrive ...