Apple Tree (可以重复走)

题目连接:http://poj.org/problem?id=2486

题意:

一颗树,n个点,n-1条边,每个点上有一个权值,求从1出发,走k步,最多能遍历到的权值。

思路:

很容易想到设dp[x][j]表示x子树分配j步能获得最多苹果数量,但是这样是不够的,因为很容易发现只有哪些回到了x点的方案的代价才是子树大小*2,但是走到最后的时候其实可以不用回到x点。

那么我们就增加状态纬度,设dp[i][j][0/1]:给树i恰好分配j步(回/不回来)i点的最大值。然后分3中情况写状态转移方程:

dp[x][j][0]=max(dp[x][j][0],dp[x][j-k][0]+dp[y][k-2][0]);   //情况①:表示遍历从左边的子树回来x点之后,去y子树,再回来x点。

dp[x][j][1]=max(dp[x][j][1],dp[x][j-k][0]+dp[y][k-1][1]);  //情况②:表示从左边回来,去y子树,不回来x点了

dp[x][j][1]=max(dp[x][j][1],dp[x][j-k][1]+dp[y][k-2][0]);  //情况3:表示从y子树回来,去左边,不回来x点了

#include <iostream>
#include <algorithm>
#include <string>
#include <string.h>
#include <vector>
#include <map>
#include <stack>
#include <set>
#include <queue>
#include <math.h>
#include <cstdio>
#include <iomanip>
#include <time.h>
#include <bitset>
#include <cmath>

#define LL long long
#define INF 0x3f3f3f3f
#define ls nod<<1
#define rs (nod<<1)+1

const double eps = 1e-10;
const int maxn = 100 + 10;
const LL mod = 1e9 + 7;

int sgn(double a){return a < -eps ? -1 : a < eps ? 0 : 1;}
using namespace std;

struct edge {
    int v,nxt;
}e[maxn<<1];

int head[maxn];
int cnt;
int f[maxn][maxn<<1][2];
int n,m;

inline void add_edge(int u,int v) {
    e[++cnt].v = v;
    e[cnt].nxt = head[u];
    head[u] = cnt;
}

inline void dfs(int x,int fa) {
    for (int i = head[x];~i;i = e[i].nxt) {
        int v = e[i].v;
        if (v == fa)
            continue;
        dfs(v,x);
        for (int j = m;j >= 1;j--) {
            for (int k = 0;k <= j;k++) {
                if (k>=2) f[x][j][0]=max(f[x][j][0],f[x][j-k][0]+f[v][k-2][0]);
                if (k>=1) f[x][j][1]=max(f[x][j][1],f[x][j-k][0]+f[v][k-1][1]);
                if (k>=2) f[x][j][1]=max(f[x][j][1],f[x][j-k][1]+f[v][k-2][0]);
            }
        }
    }
}

int main() {
    while (cin >> n >> m) {
        cnt = 0;
        memset(head,-1, sizeof(head));
        memset(f,-0x3f, sizeof(f));
        for (int i = 1;i <= n;i++) {
            int val;
            cin >> val;
            f[i][0][1] = f[i][0][0] = val;
        }
        for (int i = 1;i < n;i++) {
            int u,v;
            cin >> u >> v;
            add_edge(u,v);
            add_edge(v,u);
        }
        dfs(1,0);
        int ans=0;
        for (int i=0;i<=m;i++)
            ans=max(ans,max(f[1][i][0],f[1][i][1]));
        cout << ans << endl;
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/-Ackerman/p/12363346.html