【模拟试题】技能树 树形DP

题目描述

  玩过Diablo的人对技能树必定是很熟悉的。一颗技能树的每一个结点都是一项技能,要学会这项技能则须要耗费必定的技能点数。只有学会了某一项技能之后,才能继续学习它的后继技能。每项技能又有着不一样的级别,级别越高效果越好,而技能的升级也是须要耗费技能点数的。有个玩家积攒了必定的技能点数,他想尽量地利用这些技能点数来达到最好的效果。所以他给全部的级别都打上了分,他认为效果越好的分数也越高。如今他要你帮忙寻找一个分配技能点数的方案,使得分数总和最高。 c++

数据范围

很小很小qwqmarkdown

样例输入

3
Freezing Arrow
Ice Arrow
3
3 3 3
15 4 6
Ice Arrow
Cold Arrow
2
4 3
10 17
Cold Arrow
None
3
3 3 2
15 5 2
10
0 0 1学习

样例输出

42ui

解题思路

我以为应该叫“技能森林”吧,为何要叫技能树。。
要把森林树转换为二叉树,而后枚举分配左子树和右子树所用的技能点数。求最大值。spa

代码

#include <bits/stdc++.h>
using namespace std;
inline int Getint(){int x=0,f=1;char ch=getchar();while('0'>ch||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
inline string Getstr(){string ret="";char ch=getchar();while(!isalpha(ch))ch=getchar();while(ch!='\n')ret+=ch,ch=getchar();return ret;}
int L[25],vl[25][25],w[25][25],v[25][25],Now[25],n,p;
namespace Dp{
    int son[25][2],tmp[25],fa[25],dp[25][6666],root=1;
    void Init(){memset(dp,-1,sizeof(dp));memset(tmp,-1,sizeof(tmp));memset(son,0,sizeof(son));}
    void Build(){
        for(int i=1;i<=n;i++)
            if(~tmp[fa[i]])
                son[tmp[fa[i]]][1]=i,tmp[fa[i]]=i;
            else
                son[fa[i]][0]=i,tmp[fa[i]]=i;
    }
    int DP(int x,int vl){
        if(!x)return 0;
        if(~dp[x][vl])return dp[x][vl];
        int Max=DP(son[x][1],vl);
        if(Now[x])
            for(int i=0;i<=vl;i++)
                Max=max(Max,DP(son[x][0],i)+DP(son[x][1],vl-i));
        int Sum1=0,Sum2=0;
        for(int i=1;i<=L[x];i++){
            if(i>Now[x])Sum1+=w[x][i],Sum2+=v[x][i];
            for(int j=0;j<=vl-Sum1;j++)
                Max=max(Max,DP(son[x][0],j)+DP(son[x][1],vl-Sum1-j)+Sum2);
        }
        return dp[x][vl]=Max;
    }
}
string fa[25];
map<string,int>Map;
void Init(){
    n=Getint();
    for(int i=1;i<=n;i++){
        Map[Getstr()]=i;
        fa[i]=Getstr();
        L[i]=Getint();
        for(int j=1;j<=L[i];j++)w[i][j]=Getint();
        for(int j=1;j<=L[i];j++)v[i][j]=Getint();
    }
    p=Getint();
    for(int i=1;i<=n;i++)Now[i]=Getint();
    for(int i=1;i<=n;i++){
        if(Map[fa[i]])Dp::fa[i]=Map[fa[i]];
        else Dp::fa[i]=0;
    }
}
int main(){
    Init();
    Dp::Init();
    Dp::Build();
    cout<<Dp::DP(Dp::son[0][0],p)<<"\n";
    return 0;
}