Neutralzz的博客

我有自己的梦想和追求!

HDU 5758 Explorer Bo (树形DP)

题目:给你一棵树,用最少的链去覆盖这棵树,求链的最小总长度。

解析:num为叶子节点数,显然链数是(num+1)/2。如果是偶数,就是叶子节点到叶子节点,如果是奇数,那么就是在奇数-1情况下的树下加一条叶子到其祖先的链。

偶数的情况:从一个非叶子节点出发,如果其子节点的叶子节点是偶数,则ans+=2,如果是奇数,ans+=1。

奇数的情况:枚举一下那条单链所在的子树。

设dp[u][i][j] 在u的子树中,u的父边需要经过i次,j表示单链是否在该子树中。j=1就额外枚举单链所在子树即可,如果单链在该子树中,那么该树中的有效叶子节点-1(即奇数变偶数,偶数变奇数)。


[code]:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>

using namespace std;
const int maxn = 2e5+5;

struct Nod{
    int b,next;
    void init(int b,int next){
        this->b=b;this->next=next;
    }
}buf[2*maxn];
int n,E[maxn],len,cnt[maxn],ans,deg[maxn];
int dp[maxn][3][2];

void init(){
    ans = len = 0;
    memset(E,-1,sizeof(E));
    memset(dp,-1,sizeof(dp));
    memset(deg,0,sizeof(deg));
}
void add_edge(int a,int b){
    buf[len].init(b,E[a]);E[a]=len++;
    buf[len].init(a,E[b]);E[b]=len++;
    deg[a]++;deg[b]++;
}

void pre_dfs(int u,int pre){
    int i,v,f = 0;
    cnt[u] = 0;
    for(i = E[u];i != -1;i = buf[i].next){
        v = buf[i].b;
        if(v == pre) continue;
        pre_dfs(v,u);
        cnt[u]+=cnt[v];
        f = 1;
    }
    if(!f) cnt[u] = 1;
}
int dfs(int u,int pre,int s1,int s2){
    if(dp[u][s1][s2]!=-1) return dp[u][s1][s2];
    int i,v,ans = 0,num = -s1,tmp;
    for(i = E[u];i != -1;i = buf[i].next){
        v = buf[i].b;
        if(v == pre) continue;
        num += cnt[v];
        if(cnt[v]&1) ans += dfs(v,u,1,0)+1;
        else ans += dfs(v,u,2,0)+2;
    }
    if(s2){
        tmp = 0x3f3f3f3f;
        for(i = E[u];i != -1;i = buf[i].next){
            v = buf[i].b;
            if(v == pre) continue;
            if(cnt[v]&1){
                if(cnt[v]==1) tmp = min(tmp,ans);
                else tmp = min(tmp,ans+dfs(v,u,2,1)+2-(dfs(v,u,1,0)+1));
            }else tmp = min(tmp,ans+dfs(v,u,1,1)+1-(dfs(v,u,2,0)+2));
        }
        ans = tmp;
    }
    return dp[u][s1][s2] = ans;
}

int main(){
    int i,j,cas,u,v;
    scanf("%d",&cas);
    while(cas--){
        scanf("%d",&n);
        init();
        for(i = 1;i < n;i++){
            scanf("%d%d",&u,&v);
            add_edge(u,v);
        }
        if(n == 2){
            puts("1");
            continue;
        }
        int root=-1,num = 0;
        for(i = 1;i <= n;i++){
            if(deg[i]!=1&&root==-1){
                root = i;
            }
            num += deg[i]==1;
        }
        pre_dfs(root,-1);
        printf("%d\n",dfs(root,-1,0,num&1));
    }

    return 0;
}




阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_26572969/article/details/52045312
个人分类: DP Mark
上一篇Hdu 5352 MZL's City (最小费用最大流)
下一篇HDU 5735 Born Slippy (分块+树上可持久化)
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭