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)]蓝精灵的请求(二分图染色+背包)

loj2983WC2019数树

联考20200608 T2 图

python学习——读取染色体长度(七:读取fasta文件)

51nod 1824染色游戏

python学习——通过命令行参数根据fasta文件中染色体id提取染色体序列