vijos P1180 选课

vijos P1180 选课

典型的树形动态规划。DP之前需要用左儿子右兄弟的方法构造树。定义d[i][j]表示在以第i个结点为根的树上选择j个结点获得的最大分数。

d[i][j]=max(d[right[i]][j]d[left[i]][k]+d[right[i]][j-k-1])0<=k<=j-1

以上状态转移方程解释为:

1、 不选择根节点,j个结点全部在右子树上选择;

2、 选择根节点,从左子树上选择k个,右子树上选择j-k-1个,0<=k<=j-1

边界条件为:

d[nil][i]=0nil=n+10<=i<=mC语言中下标不能从-1开始,所以把nil的值设为n+1,因为n+1这个结点是不存在的。

d[i][0]=00<=i<=n+1

以下是我的代码:

#include < stdio.h >
#define  MAXN 302
typedef 
struct
{
    
long left,right;
}
Tree;
long  n,m,nil,ans,s[MAXN] = {0} ,d[MAXN][MAXN];
Tree tree[MAXN];
long  max( long  a, long  b)
{
    
return (a>b?a:b);
}

void  ins( long  father, long  son)
{
    
long p;
    
if(tree[father].left==nil)
      tree[father].left
=son;
    
else
    
{
       p
=tree[father].left;
       
while(tree[p].right!=nil)
         p
=tree[p].right;
       tree[p].right
=son;
    }

}

void  init()
{
    
long i,j,t;
    scanf(
"%ld%ld",&n,&m);
    nil
=n+1;
    
for(i=0;i<=n;i++)
    
{
       tree[i].left
=nil;
       tree[i].right
=nil;
    }
// Clear
    for(i=1;i<=n;i++)
    
{
       scanf(
"%ld%ld",&t,&s[i]);
       ins(t,i);
    }

    
for(i=0;i<=nil;i++)
      
for(j=0;j<=m;j++)
      
{
         
if(i==nil||j==0) d[i][j]=0;
         
else d[i][j]=-1;
      }

    
}

long  dp( long  node, long  sum)
{
    
long i;
    
if(d[node][sum]>=0)
      
return d[node][sum];
    
// 已经计算过 
    d[node][sum]=dp(tree[node].right,sum);
    
for(i=0;i<=sum-1;i++)
      d[node][sum]
=max(d[node][sum],dp(tree[node].left,i)+dp(tree[node].right,sum-i-1)+s[node]);
    
return d[node][sum];
}

int  main()
{
    freopen(
"score.in","r",stdin);
    freopen(
"score.out","w",stdout);
    init();
    ans
=dp(tree[0].left,m);
    printf(
"%ld\n",ans);
return 0;
}

你可能感兴趣的:(vijos P1180 选课)