树形DP(访问艺术馆)
来源:互联网 发布:威海淘宝培训学校 编辑:程序博客网 时间:2024/04/30 12:30
皮尔是一个出了名的盗画者,他经过数月的精心准备,打算到艺术馆盗画。艺术馆的结构,每条走廊要么分叉为二条走廊,要么通向一个展览室。皮尔知道每个展室里藏画的数量,并且他精确地测量了通过每条走廊的时间,由于经验老道,他拿下一副画需要5秒的时间。你的任务是设计一个程序,计算在警察赶来之前,他最多能偷到多少幅画。
输入描述 Input Description
第1行是警察赶到得时间,以s为单位。第2行描述了艺术馆得结构,是一串非负整数,成对地出现:每一对得第一个数是走过一条走廊得时间,第2个数是它末端得藏画数量;如果第2个数是0,那么说明这条走廊分叉为两条另外得走廊。数据按照深度优先得次序给出,请看样例
输出描述 Output Description
输出偷到得画得数量
样例输入 Sample Input
60
7 0 8 0 3 1 14 2 10 0 12 4 6 2
样例输出 Sample Output
2
数据范围及提示 Data Size & Hint
s<=600
走廊的数目<=100
这题是OI的经典题,不难,注意一点,原题是用文件输入输出的,但是这里的提交直接标准输入输出即可
这题的题意很清晰,明说了是二叉树(而且只能在两个孩子的节点和叶子节点)。
注意输入给出的信息,对于一对数据,a,b,a指通过走廊的时间,那是不是树中边的信息呢?不是的,应该是点的信息。树中每一个点都应该包含两个信息,就是时间花费和它有多少张画,对于非叶子节点而言,它的画数都是0,而时间是有的,对于叶子节点,除了有画数外,它也是有时间花费的
另外偷东西是要进去和出来的,所以如果经过了某个点往下走,就必定会经该店返回(树的性质可知),所以花费其实是两倍,所以我们在一开始保存点的花费的时候,就直接将时间花费保存为两倍,这样就相当于做到了返回
最后说一次DP思想
dp[rt][time]表示在rt这个点,剩下time时间能偷到最多的画
1.虽然时间有time,但要先花费掉通过该点的时间,tt=time-t[rt].cost
2.然后在tt时间内dp,dp[rt][time]= max{ dp[lch][i] + dp[rch][tt-i] }
这个方程很容易理解,一半时间去左边偷一半时间去右边偷,两者相加,再取最大值
3.而对于叶子节点,同样有时间花费的,所以同样先计算出tt,但是计算出tt后不用再递归了,而是计算在tt时间内最多可以拿多少画,并且这里肯定是尽量拿,只要时间还够的
但是注意一点,不能tt/5,因为时间够,但是可能画不够。。。我就是这样纠结了一下,才想起这个问题
至于怎么建树,输入已经是按照前序遍历序列给出的,那么就顺着输入,来个递归建树即可
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<iostream>
#include<algorithm>
using namespace std ;
#define N 6500
#define T 650
int n ;
struct node
{
int lch,rch,val,cost;
}t[N];
struct aa
{
int first,second;
}a[N];
int dp[N][T];
void buile(int &m) //建树
{
int rt = m ;
t[rt].cost = 2*a[rt].first ; t[rt].val = a[rt].second ; //把经过走廊的来回时间花费算出来。
if(a[m].second) //如果是叶子
{
t[rt].lch=t[rt].rch=-1; //没有左右孩子
return ;
}
t[rt].lch=m+1; //左孩子是下一个节点
buile(++m); //以左孩子为根节点继续建树
t[rt].rch=m+1; //右孩子是下一个节点
buile(++m); //以右孩子为根节点继续建树
}
int dfs(int rt, int time) // dp[rt][time]表示,在rt这个节点(岔口),剩余time时能偷到的最大副画
{
if(dp[rt][time]!=-1) return dp[rt][time]; //如果有答案,就结束返回
if(time==0) return dp[rt][time]=0; //时间还剩0,则一副也偷不到
if(t[rt].lch==-1) //是叶子
{
int c;
if( t[rt].val*5 <= time-t[rt].cost ) c =t[rt].val ; //如果见过走廊后的剩余时间可以全部偷完画,就赋值
else c = (time-t[rt].cost)/5 ; //否则偷不完
return dp[rt][time]=c ; //返回结果
}
dp[rt][time]=0; //初始化
int tt = time - t[rt].cost ; //经过走廊后的剩余时间,
for(int i = 0; i <= tt ; i++) //枚举一部分往左孩子去偷,剩余部分时间往右孩子那边去偷
{
int s1=dfs(t[rt].lch,i); //往做孩子方向偷的最多的画
int s2=dfs(t[rt].rch,tt-i); //往右孩子那边偷的最多的画
dp[rt][time]=max( dp[rt][time] , s1+s2 ); //比较。。
}
return dp[rt][time] ;
}
int main()
{
int time , n = 0;
scanf("%d",&time);
while(scanf("%d%d",&a[n].first,&a[n].second)!=EOF) n++ ;
int m=0;
buile(m); //以0为根节点建树
memset(dp,-1,sizeof(dp));
dfs(0,time);
printf("%d",dp[0][time]); //0节点,剩余time时间能偷到的最大画就是结果
return 0;
}
- 树形DP(访问艺术馆)
- 【树形dp】访问艺术馆
- 一、树形dp(1)访问艺术馆
- codevs1163 访问艺术馆(树形dp)
- 访问艺术馆 codevs1163 树形dp
- 树形dp 访问艺术馆(又称访问美术馆)
- 【树形DP】wikioi 1163 访问艺术馆
- wikioi 1163 访问艺术馆 树形dp
- CodeVS 1163 访问艺术馆(树形DP)
- 【Codevs1163】访问艺术馆 树形dp 记忆化搜索(8/1000)
- 【树形dp】【记忆化】访问艺术馆 WikiOI 1163
- codevs1163 访问艺术馆(树型dp)
- 访问艺术馆
- 访问艺术馆
- 访问艺术馆(树型动态规划)
- wikioi-天梯-进入省队-树状dp-1163:访问艺术馆
- wikioi p1163 访问艺术馆
- 1163 访问艺术馆
- 测试人员如何提交程序员无法拒绝的BUG
- 通过qt将二维数组中的像素点显示成一张图片
- error: implicit declaration of function ‘pthread_mutexattr_settype’ 引出GNU_SOURCE探索
- NSInvocation的使用
- An error (-5006: 0×80070002) has occurred while running the setup
- 树形DP(访问艺术馆)
- 100 的阶乘末尾有多少个0? .
- 解決BufferedReader BufferedWrite 读写UTF-8文件中文乱码
- 签到
- javascript深入理解js闭包
- 史玉柱自述:我是这么来做产品与营销的
- HDU2192:MagicBuilding
- [观察者模式]当观察者模式遇到突如其来的“飓风”——“天气”主题与“学校”和“公司”两个观察者之间的故事
- html—JavaScript是什么?