[树形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

 

posted @ 2018-08-09 20:02  Vagari  阅读(264)  评论(0编辑  收藏  举报