CF1029E Tree with Small Distances

题目描述

给定一棵树。要求往树中加入一些边使得从1到其他节点的距离至多是2 。 输出加入边的最小数量。(边全部都是无向的)

题解:好多人都说是贪心,但是我写的是树形dp。

(这道题实在太像小胖守皇宫了)

先贪一步,每条边都由1连出,另一端距离为1。因此可以更新其父亲和儿子。

dp[ u ][ 0 / 1 / 2]:u点由自己/儿子/父亲更新。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 200050
int n,hed[N],cnt;
struct EG
{
    int to,nxt;
}e[2*N];
void ae(int f,int t)
{
    e[++cnt].to = t;
    e[cnt].nxt = hed[f];
    hed[f] = cnt;
}
int dp[N][3];
void dfs(int u,int fa)
{
    dp[u][0]=1;
    int mn = 0x3f3f3f3f,y=1;
    for(int j=hed[u];j;j=e[j].nxt)
    {
        int to = e[j].to;
        if(to==fa)continue;
        y=0;
        dfs(to,u);
        dp[u][0]+=min(dp[to][0],min(dp[to][1],dp[to][2]));
        dp[u][2]+=min(dp[to][0],dp[to][1]);
        dp[u][1]+=min(dp[to][0],dp[to][1]);
        if(mn>dp[to][0]-dp[to][1])mn=dp[to][0]-dp[to][1];
    }
    if(mn>0)dp[u][1]+=mn;
    if(y)dp[u][1]=0x3f3f3f3f;
}
int main()
{
    scanf("%d",&n);
    for(int f,t,i=1;i<n;i++)
    {
        scanf("%d%d",&f,&t);
        ae(f,t),ae(t,f);
    }
    dfs(1,0);
    int ans = 0;
    for(int j=hed[1];j;j=e[j].nxt)
    {
        int to = e[j].to;
        ans+=dp[to][0]-1;
    }
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2018-10-22 21:10  LiGuanlin  阅读(166)  评论(6编辑  收藏  举报