码迷,mamicode.com
首页 > 其他好文 > 详细

Test 6.29 T2 染色

时间:2019-06-30 23:13:28      阅读:202      评论:0      收藏:0      [点我收藏+]

标签:define   子节点   fine   lin   test   mat   sse   输入格式   inline   

问题描述

于是 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 染色

标签:define   子节点   fine   lin   test   mat   sse   输入格式   inline   

原文地址:https://www.cnblogs.com/LSlzf/p/11111677.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!