UVA1218 Perfect Service(染色问题--树形DP)(好题,通法)

题意:一棵树,进行染色,每个没染色的节点恰好和一个染色的节点相连,求染色的节点最少的个数X(以下均以X代表子问题的解)

思路:树形DP,细化状态,从而对每个节点的每种状态互相递推

这里如何细化状态是难点,而且也是这类难题的共同问题

很容易知道每个节点i至少两个状态:dp[i][0]: i没染上色时以i的子树的X。dp[i][1]: i被染色以i为子树的X

但是仅仅这两个状态无法实现状态转移因为:

dp[u][0]=sum(dp[v][0],dp[v][1])+1  (dp[u][0]可以找到状态转移关系,dp[u][0]和u的父亲没关系)

但是dp[u][1]不仅仅与u的儿子有关系,也和u的父亲有关系,比如当他的父亲染了色,u的儿子必须全没染色,当u的父亲没染色,那么u的儿子必须有一个染了色

所以再添加一个状态来表示父亲的情况:dp[u][2],表示u和u的父亲都没染色,dp[u][1]改成u没染色但u的父亲染了色

这样递推关系就可以写出来了。

所以这类树形dp,要学会适当的添加状态,如何细化状态

//	Accepted	C++	0.016	2015-03-14 12:41:27
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;

const int N= 1e4+1e2;
const int inf = 0x3f3f3f3f;
int n,op;
struct Edge
{
    int v;
    Edge(int _v=0) : v(_v) {};
};
int dep[N]; //每个节点的深度
int fa[N];  //每个节点的父亲节点
int mdep;
int dp[N][3]; //每个节点为根的子树三个状态互相递推
vector<Edge> es[N];
void dfs(int u,int pa)
{
    fa[u]=pa;
    if(u==1) dep[u]=0;
    else dep[u]=dep[pa]+1;
    mdep=max(mdep,dep[u]);
    for(int i=0;i<es[u].size();i++)
    {
        int v=es[u][i].v;
        if(v==pa) continue;
        dfs(v,u);
    }

}
void ini()
{
    for(int i=1;i<=n;i++) es[i].clear();
    mdep=-1;
    memset(dp,0,sizeof(dp));
}
void debug()
{
    printf("mdep=%d\n",mdep);
    printf("\n0:");
    for(int i=1;i<=n;i++) printf("%11d",dp[i][0]);
    printf("\n1:");
    for(int i=1;i<=n;i++) printf("%11d",dp[i][1]);
    printf("\n2:");
    for(int i=1;i<=n;i++) printf("%11d",dp[i][2]);
    puts("");
}
int main()
{
    while(scanf("%d",&n),~op)
    {
        ini();
        int u,v;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            es[u].push_back(Edge(v));
            es[v].push_back(Edge(u));
        }
        scanf("%d",&op);
        dfs(1,0);
        for(int l=mdep;l>=0;l--)
            for(int u=1;u<=n;u++)
                if(dep[u]==l)
                {
                    int sum1=0,sum2=0;
                    int sz=es[u].size();
                    for(int j=0;j<sz;j++)
                    {
                        int v=es[u][j].v;
                        if(v==fa[u]) continue;
                        sum1+=min(dp[v][0],dp[v][1]);
                        if(sum1>inf) sum1=inf; //防止爆int
                        sum2+=dp[v][2];
                        if(sum2>inf ) sum2=inf;
                    }
                    dp[u][0]=sum1+1;
                    dp[u][1]=sum2;

                    for(int j=0;j<sz;j++)
                    {
                        int v=es[u][j].v;
                        if(v==fa[u]) continue;

                        else {
                            dp[u][2]=inf;
                            dp[u][2]=min(dp[u][2],dp[u][1]-dp[v][2]+dp[v][0]);
                        }
                    }
                    if(sz==1&&u!=1) dp[u][2]=inf; //叶节点的一个边界,所以要判根
                }

        printf("%d\n",min(dp[1][0],dp[1][2]));
       // debug();
    }
    return 0;
}
时间: 2024-12-18 02:34:33

UVA1218 Perfect Service(染色问题--树形DP)(好题,通法)的相关文章

【Luogu】P3155叶子的染色(树形DP)

题目链接 树形DP水题qwq. 设f[i][j]是以i为根的子树,染成j色,且满足内部需求的最少染色节点数. 设to是x的子节点,那么状态转移方程如此设计: 1.f[i][0] 这个状态表示i不染色,那显然很好办,对于每个to从f[to][1],f[to][2]和f[to][0]里选一个最小的即可. 转移方程$f[x][0]=\sum\limits_{to}min(f[to][1],f[to][2],f[to][0])$ 2.f[i][1] 此时i染成黑色.那么对于每个to我们发现,既可以让它继

POJ 1155 TELE 背包型树形DP 经典题

由电视台,中转站,和用户的电视组成的体系刚好是一棵树 n个节点,编号分别为1~n,1是电视台中心,2~n-m是中转站,n-m+1~n是用户,1为root 现在节点1准备转播一场比赛,已知从一个节点传送数据到达另一个节点,电视台需要一定的费用 若可以传送数据到达用户的节点n-m+1~n,这些用户各自愿意支付一定的费用给电视台 现在电视台希望在不亏本的情况下为尽量多的用户转播比赛 输出最多可以为多少用户转播比赛 背包类型的树形DP第一题 dp[i][j]表示以节点i为根的子树有j个用户获得转播,电视

URAL 1039 Anniversary Party 树形DP 水题

1039. Anniversary Party Time limit: 0.5 secondMemory limit: 8 MB Background The president of the Ural State University is going to make an 80'th Anniversary party. The university has a hierarchical structure of employees; that is, the supervisor rela

树形DP经典题

题目传送门 题意: 给出一棵树,求离每个节点最远的点的距离 思路: 把无根树转化成有根树分析, 对于上面那棵树,要求距结点2的最长距离,那么,就需要知道以2为顶点的子树(蓝色圈起的部分,我们叫它Tree(2)),距顶点2的最远距离L1 还有知道2的父节点1为根节点的树Tree(1)-Tree(2)部分(即红色圈起部分),距离结点1的最长距离+dist(1,2) = L2,那么最终距离结点2最远的距离就是max{L1,L2} f[i][0],表示顶点为i的子树的,距顶点i的最长距离 f[i][1]

POJ 3342 树形DP入门题

题目意思和POJ2342一样,只是多加了一个条件,如果最大方案数唯一,输出Yes,不唯一输出No dp的是时候多加一个变量记录答案是否唯一即可 #include "stdio.h" #include "string.h" #include "vector" using namespace std; struct node { int fa; vector<int>child; }data[210]; struct comp { int

POJ 1947 树形DP入门题

给出N个点,N-1个关系,建出树形图,问最少减去几个边能得到节点数为P的树.典型树形DP题 dp[cur][j] :记录cur结点,要得到一棵j个节点的子树去掉的最少边数 转移方程用的背包的思想 对当前树的每一个子树进行计算 砍掉此子树:   dp[cur][j]=dp[cur][j]+1; 不砍掉:           for (l=0;l<=j;l++)  dp[cur][j]=Min(dp[cur][j],dp[cur][l]+dp[next][j-l]); 枚举从该树中留l个节点其他由新

POJ 2342 树形DP入门题

有一个大学的庆典晚会,想邀请一些在大学任职的人来参加,每个人有自己的搞笑值,但是现在遇到一个问题就是如果两个人之间有直接的上下级关系,那么他们中只能有一个来参加,求请来一部分人之后,搞笑值的最大是多少. 树形DP入门题. DP部分: dp[i][0]表示职员i不来参加party,以i为根的子树的最大搞笑值, dp[i][1]表示职员i来参加party,以i为根的子树的最大搞笑值. 转移方程: dp[cur][1]+=dp[next][0]; dp[cur][0]+=Max(dp[next][1]

URAL 1018 Binary Apple Tree 树形DP 好题 经典

1018. Binary Apple Tree Time limit: 1.0 secondMemory limit: 64 MB Let's imagine how apple tree looks in binary computer world. You're right, it looks just like a binary tree, i.e. any biparous branch splits up to exactly two new branches. We will enu

P2016 战略游戏——树形DP大水题

P2016 战略游戏 树形DP 入门题吧(现在怎么是蓝色标签搞不懂): 注意是看见每一条边而不是每一个点(因为这里错了好几次): #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=3010; int pre[maxn],last[maxn],other[maxn],l; void add(int x,int y) { l++; pre[l]