zoukankan      html  css  js  c++  java
  • hdu 4616 Game(树形DP)

    题意:
    一颗有n个节点的树,每个节点有val值和c(1-有陷阱,0-无陷阱)值,给出最大可踩陷阱数k。在树中任取一点作为起点,经过某点就取得该点的val值,
    踩到第k个陷阱后马上停止,而且不能走已走过的点。
    求最大累计val值。
    暴力方法:每点进行一次深搜求最大值。(这样竟然可以过= =,703ms)
    树形DP:
    子问题:最大值转化为求一个节点某子树的最大值和树的其他部分的最大值和。
    状态:dp[u][j]表示从以u为根,从u子树中某点走到u经过j个陷阱时的最大val值。
    难点:与“不超过 k 个求最大的长度”不同的是,该题是达到k个就马上停止
    所以增加一维表示方向,即dp[u][j][0]表示从非陷阱点走到u,dp[u][j][1]表示从陷阱点走到u
    更详细解释,见代码注释

    暴力:

     1 #include <cstdio>
     2 #include <cstring>
     3 #define  N 50005
     4 
     5 struct Edge
     6 {
     7     int e, next;
     8 }edge[N*2];
     9 
    10 int head[N], eNum;
    11 int c[N], val[N], n, k, ans;
    12 
    13 void init()
    14 {
    15     memset(head, -1sizeof(head));
    16     eNum = 0; ans = 0;
    17 }
    18 
    19 void AddEdge(int u, int v)
    20 {
    21     edge[eNum].e = v;
    22     edge[eNum].next = head[u];
    23     head[u] = eNum++;
    24 }
    25 
    26 int max2(int x, int y)
    27 {
    28     return x > y ? x : y;
    29 }
    30 
    31 void dfs(int u, int fa, int cur, int cc)
    32 {
    33     if(cc>k) return;
    34     if(cc==k)
    35     {
    36         ans = max2(ans, cur);
    37         return;
    38     }
    39     ans = max2(ans, cur);
    40     for(int i=head[u]; i!=-1; i=edge[i].next)
    41     {
    42         int v = edge[i].e;
    43         if(v==fa) continue;
    44         dfs(v, u, cur + val[v], cc + c[v]);
    45     }
    46 }
    47 
    48 int main()
    49 {
    50     int t;
    51     scanf("%d",&t);
    52     while(t--)
    53     {
    54         scanf("%d%d",&n,&k);
    55         for(int i=0; i<n; i++)
    56             scanf("%d%d",&val[i],&c[i]);
    57         init();
    58         int u, v;
    59         for(int i=0; i<n-1; i++)
    60         {
    61             scanf("%d%d",&u,&v);
    62             AddEdge(u, v);
    63             AddEdge(v, u);
    64         }
    65         for(int i=0; i<n; i++)
    66         {
    67             dfs(i,-1,val[i],c[i]);
    68         }
    69         printf("%d ",ans);
    70     }
    71     return 0;
    72 }
    View Code

    树形DP:

     1 #include <cstdio>
     2 #include <cstring>
     3 #define  N 50005
     4 #define INF 99999999
     5 
     6 struct Edge
     7 {
     8     int e, next;
     9 }edge[N*2];
    10 
    11 int head[N], eNum;
    12 int c[N], val[N], n, k, ans, dp[N][4][2];
    13 
    14 void init()
    15 {
    16     memset(head, -1sizeof(head));
    17     eNum = 0; ans = 0;
    18     for(int i=0; i<n; i++)
    19     {
    20         for(int j=0; j<4; j++)
    21         {
    22             for(int l=0; l<2; l++)
    23                 dp[i][j][l] = -INF;
    24         }
    25     }
    26 }
    27 
    28 void AddEdge(int u, int v)
    29 {
    30     edge[eNum].e = v;
    31     edge[eNum].next = head[u];
    32     head[u] = eNum++;
    33 }
    34 
    35 int max2(int x, int y)
    36 {
    37     return x > y ? x : y;
    38 }
    39 
    40 void dfs(int u, int fa)
    41 {
    42     dp[u][c[u]][c[u]] = val[u]; //初始化dp[u][0][0] 或 dp[u][1][1]
    43     for(int i=head[u]; i!=-1; i=edge[i].next)
    44     {
    45         int v = edge[i].e;
    46         if(v==fa) continue;
    47         //先求从子节点子树到子节点的最大值
    48         dfs(v, u);
    49         //用u节点子树到u节点的最大值 和 从子节点子树到子节点的最大值 和 更新ans
    50         for(int j=0; j<=k; j++) //-u
    51         {
    52             for(int l=0; l+j<=k; l++)//-v
    53             {
    54                 ans = max2(ans, dp[u][j][1]+dp[v][l][1]); // 1 -> 1
    55                 if(j+l!=k) ans = max2(ans, dp[u][j][0]+dp[v][l][0]); // 0 -> 0
    56                 ans = max2(ans, dp[u][j][0]+dp[v][l][1]); // 0 -> 1 dp[v][0][1] 为-INF
    57                 ans = max2(ans, dp[u][j][1]+dp[v][l][0]); // 0 -> 1 dp[u][0][1] 为-INF
    58             }
    59         }
    60         for(int j=0; j<k; j++)
    61         {
    62             dp[u][j+c[u]][1] = max2(dp[u][j+c[u]][1],dp[v][j][1]+val[u]); //用子节点更新u点
    63             dp[u][j+c[u]][0] = max2(dp[u][j+c[u]][0],dp[v][j][0]+val[u]);
    64         }
    65         if(c[u]==0) dp[u][k][1] = max2(dp[u][k][1], dp[v][k][1]+val[u]); //这里漏了,存在ans = dp[v1][0][0] + dp[u][k][1]的可能
    66     }
    67 }
    68 
    69 int main()
    70 {
    71     int t;
    72     scanf("%d",&t);
    73     while(t--)
    74     {
    75         scanf("%d%d",&n,&k);
    76         for(int i=0; i<n; i++)
    77             scanf("%d%d",&val[i],&c[i]);
    78         init();
    79         int u, v;
    80         for(int i=0; i<n-1; i++)
    81         {
    82             scanf("%d%d",&u,&v);
    83             AddEdge(u, v);
    84             AddEdge(v, u);
    85         }
    86         dfs(0,-1);
    87         printf("%d ",ans);
    88     }
    89     return 0;
    90 }
    View Code
  • 相关阅读:
    卡诺图简单逻辑化简与五变量卡诺图化简
    flash读写学习笔记与spi接口及简单测试验证(三)
    疯狂的订餐系统软件需求分析挑战之旅4
    .NET(C#):谈谈各种结束进程的方法
    疯狂的订餐系统软件需求分析挑战之旅3
    疯狂的订餐系统软件需求分析挑战之旅5
    找零
    ASP.NET MVC3 Razor视图引擎基础语法
    做了8年软件开发了,年龄大了,想要转行做测试,大家给点意见
    想搞一个 代码仓库的东西,不知道大家有没有兴趣啊
  • 原文地址:https://www.cnblogs.com/byluoluo/p/3654212.html
Copyright © 2011-2022 走看看