zoukankan      html  css  js  c++  java
  • hdu 4714

    一个树形dp的题,又是一个涉及不深的领域  = =;

    不过在网上看到了大神用很巧的思路解决了这个题;

    大神的思路就是:

    从树的底部往上看:如果一棵子树拥有两个及以上的叶子节点,可以将这棵子树与大树分离,并且将子树化成一条直线;

    为什么这样子是最优呢?我不会证明,但我觉得这种情况可以保留最多不被删除的边;

    代码:

     1 #pragma comment(linker,"/STACK:1024000000,1024000000")
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<queue>
     5 #include<vector>
     6 #define maxn 1000005
     7 using namespace std;
     8 
     9 vector<int>ve[maxn];
    10 bool v[maxn];
    11 int ans;
    12 int dfs(int a)
    13 {
    14     v[a]=1;
    15     int l=ve[a].size(),res=0;
    16     for(int i=0; i<l; i++)
    17         if(!v[ve[a][i]])
    18             res+=dfs(ve[a][i]);
    19     if(res>=2)
    20     {
    21         if(a==1)ans+=res-2;
    22         else ans+=res-1;
    23         return 0;
    24     }
    25     else return 1;
    26 }
    27 
    28 int main()
    29 {
    30     int t,n,a,b;
    31     scanf("%d",&t);
    32     while(t--)
    33     {
    34         ans=0;
    35         scanf("%d",&n);
    36         for(int i=1; i<=n; i++)
    37             ve[i].clear();
    38         for(int i=1; i<n; i++)
    39         {
    40             scanf("%d%d",&a,&b);
    41             ve[a].push_back(b);
    42             ve[b].push_back(a);
    43         }
    44         dfs(1);
    45         printf("%d
    ",2*ans+1);
    46         memset(v,0,sizeof v);
    47     }
    48     return 0;
    49 }
    View Code

    利用dp的思想:将整棵树拆成N个单枝(所有点的度小于2),所需的cost即为2*N-1(拆成N个单枝需 N-1 cost,合成一个环需要 N cost)。

      可用树形DP求出N最小的情况,用dp[i][j]表示以i为根的可用度为j的最小单枝数。
    状态转移方程:dp[root][0]=min(dp[root][0]+dp[son][0],dp[root][1]+dp[son][1]-1)
           dp[root][1]=min(dp[root][1]+dp[son][0],dp[root][2]+dp[son][1]-1)
           dp[root][2]=dp[root][2]+dp[son][0]
    代码:
     1 #pragma comment(linker,"/STACK:1024000000,1024000000")
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<queue>
     5 #include<vector>
     6 #define maxn 1000005
     7 using namespace std;
     8 
     9 vector<int>ve[maxn];
    10 bool v[maxn];
    11 int dp[maxn][3];
    12 int ans;
    13 
    14 void dfs(int a)
    15 {
    16     v[a]=1;
    17     dp[a][0]=dp[a][1]=dp[a][2]=1;
    18     int l=ve[a].size();
    19     for(int i=0;i<l;i++)
    20     {
    21         int u=ve[a][i];
    22         if(!v[u])
    23         {
    24             dfs(u);
    25             dp[a][0]=min(dp[a][0]+dp[u][0],dp[a][1]+dp[u][1]-1);
    26             dp[a][1]=min(dp[a][1]+dp[u][0],dp[a][2]+dp[u][1]-1);
    27             dp[a][2]=dp[a][2]+dp[u][0];
    28         }
    29     }
    30 }
    31 
    32 int main()
    33 {
    34     int t,n,a,b;
    35     scanf("%d",&t);
    36     while(t--)
    37     {
    38         memset(dp,0,sizeof dp);
    39         ans=0;
    40         scanf("%d",&n);
    41         for(int i=1; i<=n; i++)
    42             ve[i].clear();
    43         for(int i=1; i<n; i++)
    44         {
    45             scanf("%d%d",&a,&b);
    46             ve[a].push_back(b);
    47             ve[b].push_back(a);
    48         }
    49         dfs(1);
    50         ans=min(dp[1][0],min(dp[1][1],dp[1][2]));
    51         printf("%d
    ",2*ans-1);
    52         memset(v,0,sizeof v);
    53     }
    54     return 0;
    55 }
    View Code
  • 相关阅读:
    剑指Offer-11.二进制中1的个数(C++/Java)
    剑指Offer-10.矩形覆盖(C++/Java)
    剑指Offer-9.变态跳台阶(C++/Java)
    UVA 1608 Non-boring sequence 不无聊的序列(分治,中途相遇)
    UVA1607 Gates 与非门电路 (二分)
    UVA 1451 Average平均值 (数形结合,斜率优化)
    UVA 1471 Defense Lines 防线 (LIS变形)
    UVA 1606 Amphiphilic Carbon Molecules 两亲性分子 (极角排序或叉积,扫描法)
    UVA 11134 FabledRooks 传说中的车 (问题分解)
    UVA 1152 4 Values Whose Sum is Zero 和为0的4个值 (中途相遇)
  • 原文地址:https://www.cnblogs.com/yours1103/p/3324286.html
Copyright © 2011-2022 走看看