其他OJ 树型DP 技能树(未通过)
http://www.cqoi.net:2012/JudgeOnline/problem.php?id=1380
题意什么的都在里面,中文题目不用解释
个人感觉是数据的问题,因为网上找遍了代码都不能通过,算了还是不纠结了
代码写得也不好,无心机改了
/* dp思想:dp[rt][p],当前节点rt,有p点,能获得的最大价值 1.可以用一部分来升级当前的这个技能,升的级数不确定,但升级需要花费点数,花费的点数 c<=p 2.不升级当前,全部用于升级子树和兄弟。但注意,若不升级当前节点而且当前节点等级是0,那么 其子树不能升级,只能升级其兄弟 */ #include <cstdio> #include <cstring> #define N 25 #define M 25 #define LEN 25 #define MAX 1010 char skill[N][LEN]; char parent[N][LEN]; int fc[N],rb[N]; int level[N]; int cost[N][M]; int val[N][M]; int start[N]; int sn; int P; int dp[N][MAX]; int search(char *name) { if(name[0]=='\0') return 0; for(int i=1; i<=sn; i++) if(!strcmp(skill[i] , name)) return i; return -1; } void input() { memset(fc,-1,sizeof(fc)); memset(rb,-1,sizeof(rb)); memset(level,0,sizeof(level)); memset(cost,0,sizeof(cost)); memset(val,0,sizeof(val)); memset(skill,0,sizeof(skill)); char name[LEN]; for(int nn=1; nn<=sn; nn++) { int i; for(i=0; (name[i]=getchar())!='\n'; ) i++; name[i]='\0'; strcpy(skill[nn] , name); //printf("%s\n",name); for(i=0; (name[i]=getchar())!='\n'; ) i++; name[i]='\0'; strcpy(parent[nn] , name); //printf("%s\n",name); scanf("%d",&level[nn]); for(i=0; i<level[nn]; i++) scanf("%d",&cost[nn][i]); for(i=0; i<level[nn]; i++) scanf("%d",&val[nn][i]); getchar(); } scanf("%d",&P); for(int i=1; i<=sn; i++) scanf("%d",&start[i]); for(int nn=1; nn<=sn; nn++) { int par=search(parent[nn]); int firson=fc[par]; fc[par]=nn; rb[nn]=firson; } } int max(int x ,int y) { return x>y?x:y; } int cal(int rt ,int s ,int e) { int ans=0; for(int i=s; i<=e; i++) ans += cost[rt][i]; return ans; } int sum(int rt ,int s,int e) { int ans=0; for(int i=s; i<=e; i++) ans += val[rt][i]; return ans; } int dfs(int rt , int p) { if(rt<0) return 0; if(p==0) return dp[rt][p]=0; if(dp[rt][p]!=-1) return dp[rt][p]; dp[rt][p]=0; for(int w=0; w<=p; w++) {//先不给当前节点升级,将点数全部用于升级子树或兄弟 int s1=0 ,s2=0; int firson=fc[rt] , bro=rb[rt]; if(start[rt]) s1=dfs(firson,p-w); s2=dfs(bro,w); dp[rt][p] = max(dp[rt][p] , s1+s2); } int c,v; for(int i=start[rt]; i<level[rt]; i++) //选择给当前节点升级,从它最初的等级开始 { c=cal(rt,start[i],i); //升这么多级需要的点数 v=sum(rt,start[i],i); //升这么多级能获得的价值 if(c>p) break; //超过当前点数了直接跳出 for(int w=0; w<=p-c; w++) //在剩下的p-c点数中分给孩子和兄弟 { int s1=0 ,s2=0; int firson=fc[rt] , bro=rb[rt]; s1=dfs(firson,p-c-w); s2=dfs(bro,w); dp[rt][p] = max(dp[rt][p] , s1+s2+v); } } return dp[rt][p]; } void solve() { memset(dp,-1,sizeof(dp)); dfs(fc[0],P); printf("%d\n",dp[fc[0]][P]); } int main() { while(scanf("%d",&sn)!=EOF) { getchar(); input(); solve(); } return 0; }