[JZOJ 5788] 餐馆

思路:
考虑树形dp。
我们设\(dp[i][j][0/1]\)表示在\(i\)为根的子树中花费\(j\)单位时间,最终回到/不必回到\(i\)的最大收益。
转移三种:
\(dp[x][j][0] = max(dp[x][j][0],dp[x][j - k - 2][0] + dp[y][k][1]);\)
\(dp[x][j][0] = max(dp[x][j][0],dp[x][j - k - 1][1] + dp[y][k][0]);\)
\(dp[x][j][1] = max(dp[x][j][1],dp[x][j - k - 2][1] + dp[y][k][1]);\)
搞定.

#include <bits/stdc++.h>
using namespace std;
inline int read() {
    int q=0,f=1;char ch = getchar();
    while(!isdigit(ch)){
        if(ch=='-')f = -1;ch=getchar();
    }
    while(isdigit(ch)){
        q=q*10+ch-'0';ch=getchar();
    }
    return q*f;
}
const int maxn = 600;
struct edge {
    int to;
    int nxt;
}e[maxn << 1];
int cnt;
int head[maxn<<1];
inline void add_edge(int u,int v) {
    e[++cnt].to = v;
    e[cnt].nxt = head[u];
    head[u] = cnt;
}
inline void Add_edge(int u,int v) {
    add_edge(u,v);
    add_edge(v,u);
    return;
}
int dp[maxn][maxn][2];
int m;int n;
int a[maxn];
inline void dfs(int x,int fa) {
    for(int i = head[x];i;i=e[i].nxt) {
        int y = e[i].to;
        if(y == fa) continue;
        dfs(y,x);
        for(int j = m;j >= 2; --j) {
            for(int k = 0;k <= m; ++k) {
                if(j - k - 2 < 0) break;
                dp[x][j][0] = max(dp[x][j][0],dp[x][j - k - 2][0] + dp[y][k][1]);
            }
        }
        for(int j = m;j >= 1; --j) {
            for(int k = 0;k <= m; ++k) {
                if(j - k - 1 < 0) break;
                dp[x][j][0] = max(dp[x][j][0],dp[x][j - k - 1][1] + dp[y][k][0]);
            }
        }
        for(int j = m;j >= 2; --j) {
            for(int k = 0;k <= m; ++k) {
                if(j - k - 2 < 0) break;
                dp[x][j][1] = max(dp[x][j][1],dp[x][j - k - 2][1] + dp[y][k][1]);
            }
        }
    }
    for(int i = m;i >= 1; --i) {
        dp[x][i][0] = max(dp[x][i][0],dp[x][i - 1][0] + a[x]);
        dp[x][i][1] = max(dp[x][i][1],dp[x][i - 1][1] + a[x]);
    }
}
int main () {
    #ifdef ONLINE_JUDGE
        freopen("dostavljac.in","r",stdin);
        freopen("dostavljac.out","w",stdout);
    #endif
    n = read(),m = read();
    for(int i = 1;i <= n; ++i) {
        a[i] = read();
    }
    for(int i = 1;i < n; ++i) {
        int x = read(),y = read();
        Add_edge(x,y);
    }
    dfs(1,0);
    printf("%d\n",dp[1][m][0]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/akoasm/p/9563839.html
今日推荐