zoukankan      html  css  js  c++  java
  • [树形DP]JZOJ 5788 餐馆

    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后就恰好没时间卖辣椒粉了。

    分析

    这题比赛时并没有想做,因为折返的骚操作让我想不到怎么搞方程(其实一开始列的方程还是挺像正解的233)

    设f[i][j][0/1]表示以i为根的子树用了j的单位时间有/无到达根的最大收益,方程显然:

    f[u][j][1]+f[v][k][0]→f[u][j+k+1][1]

    f[u][j][0]+f[v][k][1]→f[u][j+k+2][1]

    f[u][j][0]+f[v][k][0]→f[u][j+k+2][0]

    然后这样是O(n2)可以证明,这里不做过多叙述

    #include <iostream>
    #include <cstdio>
    using namespace std;
    const int N=501;
    struct Edge {
        int u,v,nx;
    }g[2*N];
    int cnt,list[N];
    int f[N][N][2];
    int a[N],d[N];
    int n,m;
    
    void Add(int u,int v) {
        g[++cnt].u=u;g[cnt].v=v;g[cnt].nx=list[u];list[u]=cnt;
    }
    
    void Init() {
        scanf("%d%d",&n,&m);
        for (int i=0;i<n;i++) scanf("%d",&a[i+1]);
        for (int i=0;i<n-1;i++) {
            int u,v;
            scanf("%d%d",&u,&v);
            Add(u,v);Add(v,u);
        }
    }
    
    void Dfs(int u,int fa) {
        for (int i=list[u];i;i=g[i].nx)
        if (g[i].v!=fa) {
            Dfs(g[i].v,u);
            for (int j=m;j>=0;j--)
            for (int k=0;k<=m;k++) {
                if (j-k-2<0) break;
                f[u][j][1]=max(f[u][j][1],f[u][j-k-2][1]+f[g[i].v][k][0]);
            }
            for (int j=m;j>=0;j--)
            for (int k=0;k<=m;k++) {
                if (j-k-1<0) break;
                f[u][j][1]=max(f[u][j][1],f[u][j-k-1][0]+f[g[i].v][k][1]);
            }
            for (int j=m;j>=0;j--)
            for (int k=0;k<=m;k++) {
                if (j-k-2<0) break;
                f[u][j][0]=max(f[u][j][0],f[u][j-k-2][0]+f[g[i].v][k][0]);
            }
        }
        for (int i=m;i>=1;i--)
        f[u][i][0]=max(f[u][i][0],f[u][i-1][0]+a[u]),
        f[u][i][1]=max(f[u][i][1],f[u][i-1][1]+a[u]);
    }
    
    int main() {
        freopen("dostavljac.in","r",stdin);
        freopen("dostavljac.out","w",stdout);
        Init();
        Dfs(1,0);
        printf("%d",max(f[1][m][0],f[1][m][1]));
        fclose(stdin);fclose(stdout);
    }
    View Code
    在日渐沉没的世界里,我发现了你。
  • 相关阅读:
    having——至少被订购过两回的订单
    产品——仓库表查询
    SQL 聚集函数使用
    select count(*)和select count(1)的区别 (转)
    SpringAOP 通知(advice)
    Spring AOP 实现原理与 CGLIB 应用
    cglib 动态代理基础篇
    模仿Struts2的Interceptor拦截器实现
    利用JDK动态代理机制实现简单拦截器
    java多线程总结二:后台线程(守护线程)
  • 原文地址:https://www.cnblogs.com/mastervan/p/9451446.html
Copyright © 2011-2022 走看看