wikioi p1163 访问艺术馆

来源:互联网 发布:网络广播方案 编辑:程序博客网 时间:2024/04/30 09:02
记得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;}



原创粉丝点击