问题描述

于是 CJK 轻轻松松就切了第一题。“好,那么来看看第二题吧。” JesseLiu 大手一挥,CJK 眼前立刻出现了一棵有 n 个节点的树。“现在,你将要为这颗树染色。你每对一个点染色,将要花费相应的费用。当你对某一点染色后,与它相邻的点也会被染色。你的任务是:在 1s 之内,求出花费最少的染色方案,使得树上所有的点都被染色。”

输入格式

第一行 n,表示树中结点的数目。 接下来的 n 行,每一行包含的整数依次为:点的标号 i(1<=i<=n),在点 i 染色费用 k,点 i 的子结点数目 m,接下来 m个数为区域 i 的子结点编号。注意:i 不一定按顺序给出,根节点不一定为 1。

输出格式

最小费用。

样例输入输出

样例输入1

6

1 30 3 2 3 4

2 16 2 5 6

3 5 0

4 4 0

5 11 0

6 5 0

样例输出1

25

样例输入2

5

1 12 2 2 3

2 10 2 4 5

3 5 0

4 11 0

5 20 0

样例输出2

15

解析

显然,这是一道树形DP题。一个节点要被染色,有且仅有以下3种情况:

  • 这个点被某个子节点覆盖。
  • 这个点被父节点覆盖。
  • 这个点自己被选中。

设\(f[i]\)表示以\(i\)为根的子树被完全覆盖的最小代价,那么以上三种情况分别设为\(f[i][0],f[i][1],f[i][2]\)。我们分别讨论3种情况的状态转移方程。

设当前节点为\(i\),父节点为\(fa\),任意子节点为\(j\)。

对于第一种,我们必须保证节点的子节点有一个被覆盖且自己没有被覆盖。那么\(f[i][0]\)只能由\(f[j][0]\)和\(f[j][2]\)推得。为了保证有子节点被染色且答案最小,我们再分两种情况:若存在\(j\)使\(f[j][2]<f[j][0]\),那么就不用管。若不存在,则将\(f[j][2]-f[j][0]\)最小的\(j\)的贡献强制转为\(f[j][2]\)。状态转移方程如下:

\[f[i][0]=\sum min(f[j][0],f[j][2])+min(f[j][2]-f[j][0],0)
\]

对于第二种,\(i\)的子节点只能被自己的儿子覆盖。注意这里不需要将父亲的代价计入,由于该状态只对第三种情况产生影响,在回到上一层时会计算的。状态转移方程如下:

\[f[i][1]=\sum f[j][0]
\]

对于第三种,则是\(j\)的三种状态取最小值再加上自己的代价。状态转移方程如下:

\[f[i][2]=\sum min(f[j][0],f[j][1],f[j][2])+w[i]
\]

注意叶子节点的边界。

代码

#include <iostream>
#include <cstdio>
#define N 100002
using namespace std;
const int inf=1<<30;
int head[N],ver[N*2],nxt[N*2],l;
int n,i,j,w[N],f[N][3];
void insert(int x,int y)
{
l++;
ver[l]=y;
nxt[l]=head[x];
head[x]=l;
}
void dfs(int x,int pre)
{
int min1=inf,id=0,sum0=0,sum1=0,sum=0;
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(y!=pre){
dfs(y,x);
int tmp=f[y][2]-f[y][0];
if(tmp<0) min1=0;
else if(tmp<min1) min1=tmp,id=y;
int t1=min(f[y][0],f[y][2]);
sum0+=t1;
sum1+=min(t1,f[y][1]);
sum+=f[y][0];
}
}
f[x][0]=sum0+min1;
if(f[x][0]==inf) f[x][0]=w[x];
f[x][1]=sum;
f[x][2]=sum1+w[x];
}
int main()
{
freopen("color.in","r",stdin);
freopen("color.out","w",stdout);
cin>>n;
for(i=1;i<=n;i++){
int x,y,m;
cin>>x;
cin>>w[x]>>m;
for(j=1;j<=m;j++){
cin>>y;
insert(x,y);
insert(y,x);
}
}
dfs(1,-1);
int ans=min(f[1][0],f[1][2]);
cout<<ans<<endl;
fclose(stdin);
fclose(stdout);
return 0;
}

总结

这道题做错,是因为DP的情况没有考虑完整导致错误。下次一定要注意。

Test 6.29 T2 染色的更多相关文章

  1. 20180706模拟赛T2——染色

    文件名: seq 题目类型: 传统题 时间限制: 1秒 内存限制: 128MB 编译优化: 无 题目描述 小A正在帮助小M刷她家的墙壁 小M家的墙可以分为\(n\)块,每段需要被刷成黑色或者白色.你可 ...

  2. 19.7.29 NOIP模拟10

    话说这次三道考试题直接可以连成一个段子:我一个辣鸡,连模板都不会打,只能跪倒在大佬面前; T1 辣鸡 但是我实在是太辣鸡了,最后干的T1,时间不够用,连暴力都没打对,无奈之下交了一个qj程序,60分( ...

  3. 「模拟8.29」chinese(性质)·physics·chemistry(概率期望)

    T1  chinese 根据他的问题i*f[i]我们容易联想到,答案其实是每种方案中每个点的贡献为1的加和 我们可以转变问题,每个点在所有方案的贡献 进而其实询问就是1-k的取值,有多少中方案再取个和 ...

  4. C# 线程间互相通信

    C#线程间互相通信主要用到两个类:AutoResetEvent和ManualResetEvent. 一.AutoResetEvent AutoResetEvent 允许线程通过发信号互相通信,线程通过 ...

  5. 8天玩转并行开发——第二天 Task的使用

    原文 8天玩转并行开发——第二天 Task的使用 在我们了解Task之前,如果我们要使用多核的功能可能就会自己来开线程,然而这种线程模型在.net 4.0之后被一种称为基于 “任务的编程模型”所冲击, ...

  6. [补档]暑假集训D6总结

    考试 不是爆零,胜似爆零= = 三道题,就拿了20分,根本没法玩好吧= = 本来以为打了道正解,打了道暴力,加上个特判分,应该不会死的太惨,然而--为啥我只有特判分啊- - 真的是惨. 讲完题觉得题是 ...

  7. 你必知必会的SQL面试题

    写在前面的话 本文参考原博<走向面试之数据库基础:一.你必知必会的SQL语句练习-Part 1>和<走向面试之数据库基础:一.你必知必会的SQL语句练习-Part 2>进行练习 ...

  8. 题解-HAOI2018全套

    去冬令营转了一圈发现自己比别人差根源在于刷题少,见过的套路少(>ω<) 于是闲来无事把历年省选题做了一些 链接放的都是洛谷的,bz偷懒放的也是链接 AM.T1 奇怪的背包 Problem ...

  9. HEOI2019 游记——240秒处的起死回生

    我还没死 Day-1 最后一场模拟赛! T1:自然数幂次和再前缀和,还是O(k)次多项式,拉格朗日插值,,,,,不能总想斯特林数啊!!! T2:神仙DP预处理... T3:AC自动机+LCA处差分+暴 ...

随机推荐

  1. linux shell的一些配置

    alias egrep='egrep --color=auto'alias fgrep='fgrep --color=auto'alias grep='grep --color=auto'alias ...

  2. jenkins执行 pod install 报错 CocoaPods requires your terminal to be using UTF-8 encoding. Consider adding the following to ~/.profile:

    错误提示是: CocoaPods 需要终端使用utf-8编码 解决办法

  3. 阶段1 语言基础+高级_1-3-Java语言高级_04-集合_07 Collections工具类_3_Collections集合工具类的方法

    第二个参数传递了一个匿名内部类.结果就出现了下面的代码 源码里面有Compare方法,对比两个参数 要重写比较的方法 对对象进行排序 创建学生类.对学生类进行排序 重写Person的ToString方 ...

  4. 测开之路一百一十:bootstrap图片

    bootstrap图片 引入bootstrap 原版的图片 bootstrap处理后的: 圆角.圆形.缩略图 自适应窗口

  5. C# Thread3——前台线程后台线程

    默认情况下,显示创建的线程都是前台线程,进程会等待内部所有的前台线程执行完才会结束退出 1.默认创建的线程都是前台线程 2.进程会等待所有的前台线程执行完而结束,如果还存在后台线程则会强行中断并且退出 ...

  6. mooc-IDEA 收藏位置和文件--003

    六.IntelliJ IDEA -收藏位置和文件(类/函数) 1.收藏自己喜欢的文件---代码 添加一个Favorites列表 定义名称 Help->Find Action... 选择Add t ...

  7. js技巧之与或运算符 || && 妙用

    如题: 假设对成长速度显示规定如下: 成长速度为5显示1个箭头:  成长速度为10显示2个箭头:  成长速度为12显示3个箭头:  成长速度为15显示4个箭头:  其他都显示都显示0各箭头.  用代码 ...

  8. 总结:String类型与Int类型的转换【实现插入操作主键自增】

    1.String类型(此类型是数字格式的字符串类型)转换成Int类型 String str = "10000"; 转换成Int类型: int num = Integer.parse ...

  9. Git-第三篇廖雪峰Git教程学习笔记(2)回退修改,恢复文件

    1.工作区 C:\fyliu\lfyTemp\gitLocalRepository\yangjie 2.版本库 我们使用git init命令创建的.git就是我们的版本库.Git的版本库里存了很多东西 ...

  10. jdk 1.7 新增

    二进制整数 JDK7提供了二进制整数的类型,只要以0b开头即可.int a = 0b0101; 下划线分隔符 针对特别长的数字,读懂它令人头疼,这时候用下划线分割数字,可增加代码可读性.long a ...