hdu 4616 树形dp

来源:互联网 发布:淘宝搜索是什么 编辑:程序博客网 时间:2024/05/16 13:47

这是一道比较特别的树形dp题目。。。。。。。或许只是我自己这样认为的吧。

1.假如u为根节点,v1,v2,v3是其子节点,v1与v2可以连成一条链,不仅仅只是父节点与子节点可以连成一条链(其实就是可以任意选取点开始)。

2。题目要求中了几个陷阱就要停止,与“最多能中的陷阱不超过n”这个条件有较大不同,要考虑所选取链头尾是否有陷阱(当链的总陷阱数达到n时)。

#include <cstdio>#include <cstdlib>#include <vector>#include <cstring>#include <algorithm>using namespace std;#define maxn 50005const long long INF=1LL<<61;int n,c;vector<int> e[maxn];int val[maxn],trap[maxn];long long int ans,dp[maxn][4][2];//第一维表示节点,第二维表示中了陷阱的个数,第三维表示起点是否有陷阱,1,代表有,0代表没有void dfs(int u,int p){    int s=e[u].size();    dp[u][trap[u]][trap[u]]=val[u];    ans=max(ans,dp[u][trap[u]][trap[u]]);    for (int i=0;i<s;i++)    {        int v=e[u][i];        if (v==p) continue;        dfs(v,u);        for (int j=0;j<=c;j++)            for (int k=0;k+j<=c;k++)            {                if (k+j<=c) ans=max(ans,dp[u][j][1]+dp[v][k][1]);                if (k+j<c)  ans=max(ans,dp[u][j][0]+dp[v][k][0]);                if (j!=c)   ans=max(ans,dp[u][j][0]+dp[v][k][1]);                if (k!=c)   ans=max(ans,dp[u][j][1]+dp[v][k][0]);    //这几个转移表示在两个子节点选取链,当然要避免dp[x][c][0]的情况出现。            }        for (int j=0;j<c;j++)        {            dp[u][j+trap[u]][0]=max(dp[u][j+trap[u]][0],dp[v][j][0]+val[u]);            dp[u][j+trap[u]][1]=max(dp[u][j+trap[u]][1],dp[v][j][1]+val[u]);//由子节点更新父节点。        }        if (!trap[u]) dp[u][c][1]=max(dp[u][c][1],dp[v][c][1]+val[u]);    }}int main(){    int cas,u,v;    scanf("%d",&cas);    while (cas--)    {        scanf("%d%d",&n,&c);        for (int i=0;i<n;i++) e[i].clear();        for (int i=0;i<n;i++)            scanf("%d%d",&val[i],&trap[i]);        for (int i=1;i<n;i++)        {            scanf("%d%d",&u,&v);            e[u].push_back(v); e[v].push_back(u);        }        ans=0;        for (int i=0;i<n;i++)            for (int j=0;j<4;j++)                for (int k=0;k<2;k++)                    dp[i][j][k]=-INF;        dfs(0,-1);        printf("%I64d\n",ans);    }    return 0;}

0 0