Test 6.29 T2 染色
Posted lslzf
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Test 6.29 T2 染色相关的知识,希望对你有一定的参考价值。
问题描述
于是 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 染色的主要内容,如果未能解决你的问题,请参考以下文章
[多校联考2019(Round 5 T2)]蓝精灵的请求(二分图染色+背包)