• hdu5758 思维,树形dp


    /*
    可以推测从叶子结点传送到叶子节点才能使传送次数最少,如果是偶数个叶子结点,那么传送leaf/2次就是答案,如果是奇数个叶子结点,则还有单独一条链需要覆盖
    dp[u]表示覆盖完u为根的子树需要走的边数,显然在满足传送次数最少的条件下,dp[u]是可以递推的
    设以u为根节点,v是u的儿子,如果v就是叶子结点,那么边u->v算一次
    如果v中有奇数个叶子节点,那么边u->v只要算一次,因为偶数个叶子结点可以互相配对,然后剩下的叶子结点会从v延伸到u
    如果v中有偶数个叶子结点,那么边u->v要算两次
    如果叶子结点是偶数,那么dp[1]就是答案,因为任何一颗子树的偶数对叶子结点互相配对,并可以向上延伸

    如果叶子结点时奇数,那么某一个叶子结点只要走到岔路口就可以停止了,不用往上走,所以配对时的向上延伸是不必要的
    那么找出这么一个叶子结点:其被多算的向上延伸距离是最大的,那么减去被多算的距离就是最优解
    那么如果f是那个额外的叶子结点,f向上走到岔路口,从岔路口一直到根,如果u->v被计算了两次,那么因为f是被外挂出来的,所以可以减去一次,
    如果u->v只被算了一次,那么要加一次
    */

    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 100005
    struct Edge{int to,nxt,cnt;}edge[maxn<<1];
    int n,ans,leaf,head[maxn],tot;
    void init(){
        memset(head,-1,sizeof head);
        tot=0;
    }
    void addedge(int u,int v){
        edge[tot].to=v;edge[tot].nxt=head[u];head[u]=tot++;
    }
    int dfs(int u,int pre){
        int cnt=0;
        for(int i=head[u];i!=-1;i=edge[i].nxt){
            int v=edge[i].to;
            if(v==pre)continue;
            edge[i].cnt=dfs(v,u);//访问子树 
            cnt+=edge[i].cnt;
        }
        ans+=cnt;
        if(cnt==0)leaf++;//树叶
        if(cnt==0||cnt%2)return 1;
        return 2; 
    } 
    int search(int u,int pre){//返回子树u的最大可以减去的覆盖边数 
        int mx=0;//一定要初始化!其实在岔路口有不往上延伸的选择!、 
        for(int i=head[u];i!=-1;i=edge[i].nxt){
            int v=edge[i].to;
            if(v==pre)continue;
            mx=max(mx,search(v,u)+(edge[i].cnt==2?1:-1));
        }
        return mx;
    }
    int main(){
        int t,u,v;
        cin>>t;
        while(t--){
            init();
            cin>>n;
            for(int i=1;i<n;i++){
                cin>>u>>v;
                addedge(u,v);
                addedge(v,u);
            }
            if(n<=2){
                printf("%d
    ",n-1);
                continue;
            }
            int root=1;
            while(edge[head[root]].nxt==-1)
                root++;//找到非叶子节点的根 
            leaf=ans=0;
            dfs(root,0);
            if(leaf%2)ans-=search(root,0);
            printf("%d
    ",ans); 
        }
    } 
  • 相关阅读:
    layoutSubviews, setNeedsLayout, layoutIfNeeded
    UIViewController 专题
    UIBarButtonItem
    ios method swizzling
    Method Swizzling
    ios逆向工程
    IOS中通知中心NSNotificationCenter应用总结
    Swift 进阶
    swift 2.0 语法 字符串
    C++Builder中MessageBox的基本用法
  • 原文地址:https://www.cnblogs.com/zsben991126/p/10350403.html
Copyright © 2020-2023  润新知