其他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;
}

 

posted @ 2013-04-10 23:24  Titanium  阅读(343)  评论(0编辑  收藏  举报