HDOJ 4616 - Game/2013多校联合第二场F 树形DP..初始化不能太随意...

        题意:

                  一个游戏的迷宫是一颗树型结构..树上的点代表了房间..每个房间里宝藏..有些房间里有陷阱..现在开始游戏..咱有C条命..若进入了有trap的房间..就会掉一条命..没有命了就Game Over了...可以从这颗树中任意的点开始沿着边走...问能获得的最多宝藏...

        题解:

                   练习赛的时候..用2维来做...果断跪了...这道题用两个维度是无法将所有的状态表示出来的...因为这道题有别于裸求树中某条链的最大价值...从某种程度上来说路径是有向的...就像第一个样例...1可以更新到2..2不能更新到0(因为到了2...拿了宝藏就Game Over了)..但是从0可以更新到2...

                   可以发现路径有向的情况为路径上有exactly C个trap....而一条合法链上出现C个trap当且仅当其至少有一头(起点 or 终点)为有trap的点...那么状态转化为三维的表示:

                   dp[node][trap_num][k]...代表以node为一头的链..其陷阱个数为trap_num...链的另一个端点是否为有trap..如此..还是用传统的树形DP来解决了...统计答案的时候保证两头至少有一个为有trap的就行了...

                   WA了几才过..原因是初始化..因为更新时实际上是要判断是否有值可以更新过来的...而我的dp值初始化为0...导致转移出了些问题....如果省去一些转移判断..dp值的初始化还是定义为负无穷大吧...这些细节一定要注意...


Program:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#define ll long long
#define eps 1e-5
#define oo 1000000007
#define pi acos(-1.0)
#define MAXN 50005
#define MAXM 2000005 
using namespace std;   
struct node
{
       int w,c;
}P[MAXN];
struct LINE
{
       int x,y,next;
}line[2*MAXN];
int Lnum,_next[MAXN],dp[MAXN][5][2],C,ans;
void addline(int x,int y)
{
       line[++Lnum].next=_next[x],_next[x]=Lnum;
       line[Lnum].x=x,line[Lnum].y=y;
}
void dfs(int x,int father)
{
       int y,k,i,j;
       dp[x][P[x].c][P[x].c]=P[x].w; 
       for (k=_next[x];k;k=line[k].next)
       {
               y=line[k].y;
               if (y==father) continue;
               dfs(y,x);
               for (i=0;i<=C;i++)
                  for (j=0;j<=C-i;j++)
                  {
                          ans=max(ans,dp[x][i][0]+dp[y][j][1]);
                          ans=max(ans,dp[x][i][1]+dp[y][j][0]);
                          ans=max(ans,dp[x][i][1]+dp[y][j][1]);
                          if (i+j==C) continue; 
                          ans=max(ans,dp[x][i][0]+dp[y][j][0]);
                  }
               //---------------------------------------------------------------               
               for (i=0;i<=C;i++) 
               {
                      dp[x][i+P[x].c][0]=max(dp[x][i+P[x].c][0],P[x].w+dp[y][i][0]);
                      dp[x][i+P[x].c][1]=max(dp[x][i+P[x].c][1],P[x].w+dp[y][i][1]); 
               }
       }
       return;
}
int main()
{     
       int T,N,i;
       freopen("input.txt","r",stdin);
       freopen("output.txt","w",stdout); 
       scanf("%d",&T);
       while (T--)
       {
              scanf("%d%d",&N,&C);
              for (i=0;i<N;i++) scanf("%d%d",&P[i].w,&P[i].c);
              memset(_next,0,sizeof(_next));
              Lnum=0;
              for (i=1;i<N;i++)
              {
                      int x,y;
                      scanf("%d%d",&x,&y);
                      addline(x,y),addline(y,x);
              }
              memset(dp,-0x3f,sizeof(dp));
              ans=0;
              dfs(0,-1);
              printf("%d\n",ans);
       }
       return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值