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

}

 

你可能感兴趣的:(dp)