技能树 题解

这是一篇关于技能树题解的文章,讨论了如何在有限的技能点数内,通过优化技能升级策略来获得最高评分的问题。文章提供了具体的输入输出格式,并给出了一个样例,包括技能描述、当前技能点数和已学习的技能级别。解题思路涉及动态规划,通过计算学到每个技能的不同花费下的价值来找出最佳分配方案。
摘要由CSDN通过智能技术生成

技能树 题解

技能树

题目

玩过 D i a b l o Diablo Diablo的人对技能树一定是很熟悉的。一颗技能树的每个结点都是一项技能,要学会这项技能则需要耗费一定的技能点数。只有学会了某一项技能以后,才能继续学习它的后继技能。每项技能又有着不同的级别,级别越高效果越好,而技能的升级也是需要 耗费技能点数的。
  有个玩家积攒了一定的技能点数,他想尽可能地利用这些技能点数来达到最好的效果。因此他给所有的级别都打上了分,他认为效果越好的分数也越高。现在他要你帮忙寻找一个分配技能点数的方案,使得分数总和最高。


输入

第一行是一个整数 n n n(1<= n n n<=20),表示所有不同技能的总数。接下来依次给出 n n n个不同技能的详细情况。每个技能描述包括5行,第一行是该技能的名称,第2行是该技能在技能树中父技能的名称,为空则表示该技能不需要任何的先修技能便能学习。第3行是一个整数 L L L(1<= L L L<=20),表示这项技能所能拥有的最高级别。第4行共有 L L L个整数,其中第 I I I个整数表示从地I-1级升到第 I I I级所需要的技能点数(0级表示没有学习过)。第5行包括 L L L个整数,其中第 I I I个整数表示从第 I I I-1级升级到第I级的效果评分,分数不超过20。在技能描述之后,共有两行,第1行是一个整数 P P P,表示目前所拥有的技能点数。接下来1行是 N N N个整数,依次表示角色当前习得的技能级别,0表示还未学习。这里不会出现非法情况。


输出

S,表示最佳分配方案所得的分数总和。


样例

input
3
Freezing Arrow
Ice Arrow
3
3 3 3
15 4 6
Ice Arrow
Cold Arrow
2
4 3
10 17
Cold Arrow

3
3 3 2
15 5 2
10
0 0 1

output
42


解题思路

f[i][j]意思为学到第i个技能花了j个技能点数得到的价值
分两种情况思考
第一种
原先有等级,不升级

 if (d[h[i].to])
 {
	 for (int j=0;j<=r;j++)
	 	 f[h[i].to][j]=f[x][j];
	 	 dfs(h[i].to,r);
	 	 for (int j=0;j<=r;j++)
	 	 	  f[x][j]=max(f[x][j],f[h[i].to][j]);
}

第二种
升级它

for (int j=d[h[i].to]+1;j<=l[h[i].to];j++)
	 	 {
	 	 	 g1+=l1[h[i].to][j];
	 	 	 g2+=l2[h[i].to][j];
	 	 	 if (r-g1<0) continue;
	 	 	 for (int k=0;k<=r-g1;k++)
	 	 	     f[h[i].to][k]=tm[k];
	 	 	 dfs(h[i].to,r-g1);
	 	 	 for (int k=g1;k<=r;k++)
	 	 	     f[x][k]=max(f[x][k],f[h[i].to][k-g1]+g2);
	 	 }

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
struct hhx{
	int to,next;
}h[500200];
int n,m,a[1020],t,tt,l[1020],l1[1020][1020],l2[1020][1020],head[1020];
int f[1020][1020],d[1020];
string s,su[1020]; 
int find(string x)
{
	for (int i=1;i<=t;i++)  //找到它在数组里是第几位
        if (x==su[i])
           return i;
    su[++t]=x;  //没出现过,加入数组
    return t;
}
void add(int x,int y)  //连接
{
	 h[++tt].to=y;
	 h[tt].next=head[x];
	 head[x]=tt;
}
void dfs(int x,int r)
{
	 int tm[120];
	 if (r<0) return;
	 for (int i=head[x];i;i=h[i].next)
	 {
	 	 for (int j=0;j<=r;j++)
	 	     tm[j]=f[x][j];
	 	 if (d[h[i].to])  //不升级
	 	 {
	 	 	for (int j=0;j<=r;j++)
	 	 	    f[h[i].to][j]=f[x][j];
	 	 	dfs(h[i].to,r);
	 	 	for (int j=0;j<=r;j++)
	 	 	    f[x][j]=max(f[x][j],f[h[i].to][j]);
	 	 }
	 	 int g1=0,g2=0;
	 	 for (int j=d[h[i].to]+1;j<=l[h[i].to];j++)  //升级
	 	 {
	 	 	 g1+=l1[h[i].to][j];
	 	 	 g2+=l2[h[i].to][j];
	 	 	 if (r-g1<0) continue;
	 	 	 for (int k=0;k<=r-g1;k++)
	 	 	     f[h[i].to][k]=tm[k];
	 	 	 dfs(h[i].to,r-g1);
	 	 	 for (int k=g1;k<=r;k++)
	 	 	     f[x][k]=max(f[x][k],f[h[i].to][k-g1]+g2);
	 	 }
	 }
}
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	{
		getline(cin,s);
		getline(cin,s);
		a[i]=find(s);
		getline(cin,s);
		int y=0;
		if (s!="")
		   y=find(s);
		add(y,a[i]);
		scanf("%d",&l[a[i]]);
		for (int j=1;j<=l[a[i]];j++) scanf("%d",&l1[a[i]][j]);
		for (int j=1;j<=l[a[i]];j++) scanf("%d",&l2[a[i]][j]); 
	}
	scanf("%d",&m);
	for (int i=1;i<=n;i++)
	    scanf("%d",&d[a[i]]);
	dfs(0,m);
	printf("%d",f[0][m]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值