HDU 5758 Explorer Bo (树形DP)

原创 2016年07月27日 14:46:54

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

解析: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;
}




版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

2016多校联合第三场 HDU5758 Explorer Bo

题目大意: 给定一颗树,每次任意选取两个点,两点之间的所有边被标记,此次操作对答案的贡献为路径的长度;问在最少选取次数的情况下整个树被标记的最小答案。思路:对于第一个问题,最少选取次数显然是(叶子节点...
  • CQU_HYX
  • CQU_HYX
  • 2016年07月27日 12:54
  • 673

2016 暑假多校训练 第三场 1007 Explorer Bo HDU 5758

#pragma comment(linker,"/STACK:1024000000,1024000000") #include #include #include #include #incl...

HDU 5758 Explorer Bo

DescriptionExplorer Bo likes exploring mazes around the world.Now he wants to explore a new maze. T...

(HDU 5754)2016 Multi-University Training Contest 3 Life Winner Bo (博弈/DP)

题意在一个n×mn\times m的棋盘左上角有一个棋子(四种类型之一),要求移动到右下角(只能往右或者往下),问都采取最优策略的情况下,先手方是否必胜(或者平局)。思路从来没做过这么奇怪的博弈题,写...

2016MUTC3-1007 Explorer Bo

最小链覆盖是(leaf+1)/2,每条路径都是从叶子到叶子(当奇数时,有且只有一条路径为叶子到祖先) 对于以i为根的子树,叶子节点为奇数个,显然一个连出去,其余互相连比较优;若叶子节点为偶数个,两个...

HDU 4003 Find Metal Mineral(树形dp,从根节点出发k个机器人遍历所有边的最小代价和)

题目链接; HDU 4003 Find Metal Mineral 题意: 给一个nn个节点和n−1n-1条边的树,每条边有权值,在给定的根节点rootroot有KK个机器人,要用这KK个机器...
  • Ramay7
  • Ramay7
  • 2016年08月08日 20:43
  • 385

HDU 3899 求所有人移动到某点的最小距离和 树形dp

题意: 给定n个点 每个点的人数 n-1条边和边权。 选取任意一点u,然后让所有人都移动到u点 问最小的移动距离和是多少 水dp #pragma comment(linker, "/STACK:102...

HDU - 2242 考研路茫茫――空调教室(树形DP+强连通分量)

题目大意:众所周知,HDU的考研教室是没有空调的,于是就苦了不少不去图书馆的考研仔们。Lele也是其中一个。而某教室旁边又摆着两个未装上的空调,更是引起人们无限YY。 一个炎热的下午,Lele照例在教...

HDU 2242 考研路茫茫——空调教室 (双连通分量+树形DP)

题目地址:HDU 2242 先用双连通分量缩点,然后形成一棵树,然后在树上做树形DP,求出每个点的子树和。然后找最小值即可。需要注意一下重边的问题,第一次返回父节点时可以忽略,因为这是反向边,然后之...

【POJ 1463】【hdu 1054】Strategic game(树形dp)

尘埃落定、洗尽铅华,转身一世琉璃白
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:HDU 5758 Explorer Bo (树形DP)
举报原因:
原因补充:

(最多只允许输入30个字)