【问题描述】
该题有多组测试数据。
每组测试数据第一行是一个整数n(1<=n<=20),表示所有不同技能的总数。
接下来依次给出n个不同技能的详细情况。
每个技能描述包括5行。
第一行是该技能的名称。
第2行是该技能在技能树中父技能的名称,名称为None则表示该技能不需要任何的先修技能便能学习。
第3行是一个整数L(1<=L<=20),表示这项技能所能拥有的最高级别。
第4行共有L个整数,其中第I个整数表示从地I-1级升到第I级所需要的技能点数(0级表示没有学习过)。
第5行包括L个整数,其中第I个整数表示从第I-1级升级到第I级的效果评分,分数不超过20。
在技能描述之后,共有两行,第1行是一个整数P,表示目前所拥有的技能点数。
接下来1行是N个整数,依次表示角色当前习得的技能级别,0表示还未学习。这里不会出现非法情况。
每组测试数据只需输出最佳分配方案所得的分数总和。
【输入样例】
3
Freezing Arrow // 翻译为:冰冻箭
Ice Arrow // 翻译为:冰箭
3
3 3 3
15 4 6
Ice Arrow
Cold Arrow // 翻译为:冰冷的箭【你tm在逗我..】
2
4 3
10 17
Cold Arrow
3
3 3 2
15 5 2
10
0 0 1
【输出样例】
42
【解析】这道题可以说是上一道题,也就是【选课(choose)(详情看上一篇报告)】的加强版。
这道题在【选课】的基础上增加了处理字符串、分等级这些比较坑爹的情况.. 当然最坑的不是这个,而是这道题还是多组数据输入输出的题目.. 也就是说我们要进行初始化..
那么说说总体思路吧..
首先就是输入流啦.. 记住输入name的时候要用【gets】输入,因为要考虑到有空格的情况..
然后输入初始的等级输入.. 这个时候我就用了一个比较巧妙地办法,也就是把输入的now[i]所在位置的得分和耗点为0,因为有时可以不选当前点而直接到孩子节点【除了now[i]为0外】..
for ( i = 1; i <= n; i ++ ){ scanf ( "%d", &now[i] ); tr[i].l[now[i]] = 0; tr[i].q[now[i]] = 0; }
接着就是一个非常暴力的森林转二叉树【上一篇报告有提及..】..
最后就是最重要的,Tree_DP的过程:
void Tree_DP ( int x, int k ){ if ( f[x][k] != -1 ) return; // 这句非常重要..不然会超时.. if ( x < 0 || k < 0 ) return; int i, j, y; Tree_DP ( tr[x].rc, k ); f[x][k] = f[tr[x].rc][k]; int suml, sumq; suml = k; sumq = 0; for ( i = now[x]; i <= tr[x].lev; i ++ ){ suml -= tr[x].l[i]; sumq += tr[x].q[i]; if ( i == 0 ) continue; if ( suml < 0 ) break; for ( j = 0; j <= suml; j ++ ){ Tree_DP ( tr[x].lc, j ); Tree_DP ( tr[x].rc, suml-j ); f[x][k] = _max ( f[x][k], f[tr[x].lc][j] + f[tr[x].rc][suml-j] + sumq ); } } }大概就是这么多吧..
记住初始化要初始化到0节点.. 【因为这个错了好多次..】
That's all.
【完整代码】
#include <cstdio> #include <cstring> #include <cstdlib> using namespace std; struct node { char name[25], fa_name[25]; int lc, rc, lev, last; int l[25], q[25]; node (){ lc = rc = last = -1; } }tr[25]; int n, now[25], m; int f[25][110]; int fip ( node x ){ int i, j, k; for ( i = 1; i <= n; i ++ ){ if ( strcmp ( x.fa_name, tr[i].name ) == 0 ) return i; } return 0; } int _max ( int x, int y ){ return x > y ? x : y; } void Tree_DP ( int x, int k ){ if ( f[x][k] != -1 ) return; if ( x < 0 || k < 0 ) return; int i, j, y; Tree_DP ( tr[x].rc, k ); f[x][k] = f[tr[x].rc][k]; int suml, sumq; suml = k; sumq = 0; for ( i = now[x]; i <= tr[x].lev; i ++ ){ suml -= tr[x].l[i]; sumq += tr[x].q[i]; if ( i == 0 ) continue; if ( suml < 0 ) break; for ( j = 0; j <= suml; j ++ ){ Tree_DP ( tr[x].lc, j ); Tree_DP ( tr[x].rc, suml-j ); f[x][k] = _max ( f[x][k], f[tr[x].lc][j] + f[tr[x].rc][suml-j] + sumq ); } } } int main (){ int i, j, k; while ( scanf ( "%d", &n ) != EOF ){ for ( i = 0; i <= n; i ++ ){ tr[i].lc = tr[i].rc = tr[i].last = -1; tr[i].lev = 0; memset ( tr[i].name, '\0', sizeof (tr[i].name) ); memset ( tr[i].fa_name, '\0', sizeof ( tr[i].fa_name ) ); memset ( tr[i].l, 0, sizeof (tr[i].l) ); memset ( tr[i].q, 0, sizeof (tr[i].q) ); } memset ( now, 0, sizeof (now) ); for ( i = 1; i <= n; i ++ ){ getchar (); gets ( tr[i].name ); gets ( tr[i].fa_name ); scanf ( "%d", &tr[i].lev ); for ( j = 1; j <= tr[i].lev; j ++ ) scanf ( "%d", &tr[i].l[j] ); for ( j = 1; j <= tr[i].lev; j ++ ) scanf ( "%d", &tr[i].q[j] ); } scanf ( "%d", &m ); for ( i = 1; i <= n; i ++ ){ scanf ( "%d", &now[i] ); tr[i].l[now[i]] = 0; tr[i].q[now[i]] = 0; } for ( i = 1; i <= n; i ++ ){ k = fip (tr[i]); if ( tr[k].last == -1 ) tr[k].lc = i; else tr[tr[k].last].rc = i; tr[k].last = i; } memset ( f, -1, sizeof (f) ); Tree_DP ( tr[0].lc, m ); printf ( "%d\n", f[tr[0].lc][m] ); } return 0; }