wikioi p1163 访问艺术馆

记得wikioi开站不久的时候,我做这题被吓住了。后来发现没什么难度。
首先dfs序记录结点信息。
Left为左孩子 right为右孩子
time表示走廊的时间 cost表示价值(如果为0 表示为分岔口)
int dfs()
这题要详细说一下。
如果记录到leaf结点
那么记录下编号old_leaf
leaf++
表示读入就要读入下一个节点
那么左孩子=dfs()
右孩子=dfs()
(dfs是有返回值的,表示节点的编号,在递归当中就可以记录孩子节点。这是一种处理技巧,知道就好。)
如果f[r][s]表示r节点在剩余s秒时的最大价值。
那么通过这个通道需要Tree[r][s].time的时间
因为不仅要进去,还有出来。那么就剩余s-Tree[r].time*2
枚举i表示左子树遍历i秒,则右子树剩余s-Tree[r].time*2-i
那么f[r][s]=max{f[Tree[r].left][i]+f[Tree[r].right][s-Tree[r].time*2-i]};
如果r为叶子节点
那么如果剩下的画在有限的时间内拿完,就会刚刚好拿到Tree[r].cost个
如果偷不完,说明剩下s-Tree[r].time2的时间,那么就可以拿Int(s-Tree[r].time*2)5个Int()表示下取整
因为如果进去可能被警察抓到,所以有可能不进入这个分叉点。
所以可以简写为

max(0,min((s-Tree[r].time*2)/5,Tree[r].cost))

#include<stdio.h>
#include<iostream>
#include<memory.h>
using namespace std;
const int MAX_N = 601;
const int root = 1;
struct node
{
	int time;
	int cost;
	int left;
	int right;
}Tree[MAX_N];
int f[MAX_N][MAX_N];
int S;
int leaf = 0;
int input()
{
	int old_leaf=++leaf;
	scanf("%d %d",&Tree[leaf].time,&Tree[leaf].cost);
	if(!Tree[leaf].cost) Tree[old_leaf].left=input(),Tree[old_leaf].right=input();
	return old_leaf;
}
int init()
{
	scanf("%d",&S);
	input();
	memset(f,-1,sizeof(f));
}
int work(int r,int s)
{
	if (f[r][s]!=-1) return f[r][s];
	if (Tree[r].cost) return max(0,min((s-Tree[r].time*2)/5,Tree[r].cost));
	int tmp = 0;
	int i;
	for (i=0;i<=s-Tree[r].time*2;i++)
	tmp = max(tmp,work(Tree[r].left,i)+work(Tree[r].right,s-Tree[r].time*2-i));
	return f[r][s]=tmp;
}
int put()
{
	printf("%d",f[root][S]);
}
int main()
{
	init();
	work(root,S);
	put();
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值