zoukankan      html  css  js  c++  java
  • HDU 5758 Explorer Bo

    思维,树形$dp$。

    首先选择一个度不为$0$的节点作为根节点,将树无根转有根。

    这题的突破口就是要求瞬间移动的次数最少。

    次数最少,必然是一个叶子节点走到另一个叶子节点,然后瞬间移动一次,再从一个叶子节点走到另一个叶子节点,然后瞬间移动一次……

    因为叶子节点总数可能是奇数,可能是偶数,那么接下来要分类讨论一下了。

    叶子节点总数为偶数:

    这种情况下,叶子节点可以两两配对。如果 下面叶子节点个数是偶数,那么$<u,v>$这条边通过的次数就是$2$;如果$v$下面叶子节点个数是偶数,那么$<u,v>$这条边通过的次数就是$1$次(画图就可以知道)。知道了每条边的通过次数,那么答案就是每条边通过次数的总和。

    叶子节点总数为奇数:

    这种情况下,与上面偶数的情况唯一不同的就是:有一个叶子节点无法配对。那么我们只需枚举哪一个叶子节点不配对即可。枚举从$root$开始,$dfs$一次就可以了。

    这种题目虽然涉及到的知识量极少,但是思维量极高,对于这种题目弱渣表示暂时完全不能独立想出来。

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<queue>
    #include<stack>
    #include<iostream>
    using namespace std;
    typedef long long LL;
    const double pi=acos(-1.0),eps=1e-8;
    void File()
    {
        freopen("D:\in.txt","r",stdin);
        freopen("D:\out.txt","w",stdout);
    }
    template <class T>
    inline void read(T &x)
    {
        char c = getchar(); x = 0;while(!isdigit(c)) c = getchar();
        while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar();  }
    }
    
    const int maxn=100000+10;
    int T,n,ans;
    struct Edge{int u,v,nx;}e[2*maxn];
    int root,h[maxn],sz;
    int f[maxn],r[maxn],d[maxn];
    
    void add(int u,int v)
    {
        e[sz].u=u; e[sz].v=v; e[sz].nx=h[u]; h[u]=sz++;
    }
    
    void dfs(int x,int fa)
    {
        int sum=0; f[x]=d[x]=0;
        for(int i=h[x];i!=-1;i=e[i].nx)
        {
            if(fa==e[i].v) continue;
            sum++; dfs(e[i].v,x); f[x]=f[x]+f[e[i].v];
            if(f[e[i].v]%2==0) d[x]=d[x]+2; else d[x]=d[x]+1;
        }
        if(sum==0) f[x]=1;
    }
    
    void Find(int x,int fa,int Ans)
    {
        for(int i=h[x];i!=-1;i=e[i].nx)
        {
            if(fa==e[i].v) continue;
            if(f[e[i].v]==1) { ans=min(ans,Ans); continue; }
            else
            {
                if(f[e[i].v]%2==0) Find(e[i].v,x,Ans-1);
                else Find(e[i].v,x,Ans+1);
            }
        }
    }
    
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&n);
            memset(h,-1,sizeof h); memset(r,sz=0,sizeof r);
    
            for(int i=1;i<=n-1;i++)
            {
                int u,v; scanf("%d%d",&u,&v);
                r[u]++; r[v]++; add(u,v); add(v,u);
            }
            if(n==2) { printf("1
    "); continue; }
            if(n==1) { printf("0
    "); continue; }
    
            for(int i=1;i<=n;i++) if(r[i]!=1) { root=i; break; }
    
            dfs(root,0); ans=0;
            for(int i=1;i<=n;i++)
            {
                if(i==root) continue;
                if(f[i]%2==0) ans=ans+2; else ans=ans+1;
            }
    
            if(f[root]%2==0) printf("%d
    ",ans);
            else { Find(root,0,ans); printf("%d
    ",ans); }
        }
        return 0;
    }
  • 相关阅读:
    一键启动frida server的cmd脚本
    AES加密的S盒和逆S盒的推导代码备份(C实现)
    windows android ndk的某些编译工具报错乱码0x5 或拒绝访问05
    cygwin的sh: line 15: $' ': command not found错误
    一种JNI混淆方案
    android上的bin/sbin/xbin等各种目录
    Mac OSX bash function 备份
    Xposed免重启调试工具类
    vscode调试vue代码
    爬取ESRI疫情地图数据
  • 原文地址:https://www.cnblogs.com/zufezzt/p/5796175.html
Copyright © 2011-2022 走看看