zoukankan      html  css  js  c++  java
  • [树形dp] Jzoj P5788 餐馆

    Description

     K妹的胡椒粉大卖,这辣味让食客们感到刺激,许多餐馆也买这位K妹的账。有N家餐馆,有N-1条道路,这N家餐馆能相互到达。K妹从1号餐馆开始。每一个单位时间,K妹可以在所在餐馆卖完尽量多的胡椒粉,或者移动到有道路直接相连的隔壁餐馆。第i家餐馆最多需要A[i]瓶胡椒粉。K妹有M个单位的时间,问她最多能卖多少胡椒粉。
     

    Input

    第一行有两个正整数N,M。
    第二行描述餐馆对胡椒粉的最大需求量,有N个正整数,表示A[i]。
    接下来有N-1行描述道路的情况,每行两个正整数u,v,描述这条道路连接的两个餐馆。

    Output

    一个整数,表示她最多能卖的胡椒粉瓶数。
     

    Sample Input

    样例1输入
    3 5
    9 2 5
    1 2
    1 3
    
    样例2输入
    4 5
    1 1 1 2
    1 2
    2 3
    3 4
    
    样例3输入
    5 10
    1 3 5 2 4
    5 2
    3 1
    2 3
    4 2
     

    Sample Output

    样例1输出
    14
    
    样例2输出
    3
    
    样例3输出
    15
     
     

    Data Constraint

    对于10%的数据,N≤20。
    对于50%的数据,N≤110。
    对于100%的数据1 ≤ N, M ≤ 500,1 ≤ A[i]≤ 10^6,
    第5到第10个测试点都有多个子测试。
     

    Hint

    在样例1的中,辣妹到达城市2后就恰好没时间卖辣椒粉了。

    题解

    • 设f[i][j][0/1]为以i为根的子树中 花费j的时间 是否走回根的最大收益(0为有,1为无)
    • 枚举下一棵子树时,可以枚举下一棵子树中所用的时间,和当前子树中用的时间
    • 考虑三种转移:
    • ①之前走过的子树回根 再走到另一棵子树不回根
    • f[i][j][1]=f[i][j-k-1][0]+f[son][k][1]
    • ②之前走过的子树回根 再走到另一棵子树也回根
    • f[i][j][0]=f[i][j-k-2][0]+f[son][k][0]
    • ③走到另一棵子子树回根 之前子树不回根
    • f[i][j][1]=f[i][j-k-2][1]+f[son][k][0]

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cmath>
     4 #include <cstring>
     5 using namespace std;
     6 struct edge { int to,from; }e[510*2];
     7 int f[510][510][2],n,m,a[510],head[510],cnt;
     8 void insert(int x,int y) { e[++cnt].to=y; e[cnt].from=head[x]; head[x]=cnt; }
     9 void dp(int x,int fa)
    10 {
    11     for (int i=head[x];i;i=e[i].from)
    12     {
    13         if (e[i].to==fa) continue;
    14         dp(e[i].to,x);
    15         for (int j=m;j>=1;j--)
    16             for (int k=0;k<=m;k++)
    17             {
    18                 if (j-k>=2)
    19                     f[x][j][1]=max(f[x][j][1],f[x][j-k-2][1]+f[e[i].to][k][0]),
    20                     f[x][j][0]=max(f[x][j][0],f[x][j-k-2][0]+f[e[i].to][k][0]);
    21                 if (j-k>=1) f[x][j][1]=max(f[x][j][1],f[x][j-k-1][0]+f[e[i].to][k][1]);
    22             }
    23     }
    24     for (int i=m;i>=1;i--)
    25     {
    26         f[x][i][0]=max(f[x][i][0],f[x][i-1][0]+a[x]);
    27         f[x][i][1]=max(f[x][i][1],f[x][i-1][1]+a[x]);
    28     }
    29 }
    30 int main()
    31 {
    32     freopen("dostavljac.in","r",stdin);
    33     freopen("dostavljac.out","w",stdout);
    34     scanf("%d%d",&n,&m);
    35     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    36     for (int i=1;i<=n-1;i++)
    37     {
    38         int u,v;
    39         scanf("%d%d",&u,&v);
    40         insert(u,v); insert(v,u);
    41     }
    42     dp(1,0);
    43     printf("%d",f[1][m][1]);
    44     return 0;
    45 }
  • 相关阅读:
    成为高级Java工程师,你必须要看的技术书籍
    MYSQL存储引擎介绍--应用场景
    RocketMq的安装使用
    调用第三方物流公司API即时查询物流信息
    移动终端处理器构成和基带芯片概述
    数据库水平切分(拆库拆表)的实现原理
    使用TortoiseGit操作分支的创建与合并
    mysql安装教程
    初步认识dubbo--小案例
    【算法】混合流体模拟demo
  • 原文地址:https://www.cnblogs.com/Comfortable/p/9451287.html
Copyright © 2011-2022 走看看