【解题报告】选课

题目来源:vijos1180.
树形DP,设f[v,num]为以v为根的子树选取num门课所能得到的最大学分。为了方便分配这num门课程,我们将题目所给的多叉树转换为二叉树。
参考资料:原理代码 .

转为二叉树后,实际上任意节点i的左孩子(包括左孩子的孩子)是i真正的子节点,而i的右孩子(包括右孩子的右孩子)是i节点的兄弟节点。故i未选时,i的所有左孩子不可选,但右孩子可以。于是得状态转移方程如下:
选v时(则左孩子(真正的孩子)可以分配):

f[v,num]=max(f[v,num],score[v]+f[tree[v,1]],i)+f[tree[v,2],num-i-1]//(0<=i<=num-1)(tree[v,1]即为v的左孩子,tree[v,2]为右孩子)

不选v时(只可全给右孩子,即兄弟节点):

f[v,num]=max(f[v,num],f[tree[v,2]],num)

从以上两个方程中取最大值即是解。
觉得写得好的话,就点个赞让我知道一下呗~
AC代码:

program vijos1180;
var n,m,i,x:integer;
	s:array[1..300]of byte;//s means score.
	tree:array[0..300,1..2]of integer;//1 left,2 right.
	f:array[1..300,0..300]of integer;
function max(a,b:integer):integer;
begin
  if(a>b)then exit(a);
  exit(b);
end;
function dp(v,num:integer):integer;
var i:integer;
begin
	if(v=0)then exit(0);
	if(f[v,num]>0)then exit(f[v,num]);
	for i:=0 to num-1 do
		f[v,num]:=max( f[v,num], s[v]+dp(tree[v,1],i)+dp(tree[v,2],num-i-1) );
	f[v,num]:=max(f[v,num],dp(tree[v,2],num));	
	exit(f[v,num]);
end;
begin
	readln(n,m);
	for i:=1 to n do begin
		readln(x,s[i]);
		if(tree[x,1]>0)then tree[i,2]:=tree[x,1];
		tree[x,1]:=i;
	end;//边读入边转二叉树。
	
	writeln(dp(tree[0,1],m));
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值