重拾算法第三天 - P1270“访问”美术馆

原题链接:P1270 - “访问”美术馆

叠甲:没AC,还剩最后一个测试用例没过,知道题解区有很多大佬,但是还是想来交流一下,看看我的代码问题在哪。

分析

原题是个很明显的树状dp,需要从房间(即叶结点)开始逐步把最优解递归到根节点;题目输入数据的顺序也按照dfs的顺序,摆明了要用上dfs。

思路

我的思路:将资源(时间)分配的情况进行枚举 + 记忆搜索:

1. 对于有房间的走廊(叶子结点),扣除2*走廊本身所需时间,计算剩下时间足够拿几幅画;

2. 对于每个走廊(父节点),扣除2*走廊本身所需时间,将剩下的时间枚举地分配给尽头的左右走廊(即子节点),记录两个子节点综合起来的最优情况。

我的代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;

const int max_n = 16390;
const int max_time = 6000;
int dp[max_n][max_time];// dp[n][i]:第n条走廊上,当限制时间为i时=取得画的数量
int limit;

// 用tree数组记录树形结构的走廊、房间。走廊i的耗时为tree[i]
// 走廊i的分叉走廊为2*i和2*i+1;
// 走廊i尽头若为房间,则tree[2*i]=画的数量,tree[2*i+1]=0。

int tree[max_n] = { 0 };

int dfs(int n, int time_limit)//time_limit:踏进走廊n之前的时限
{
	time_limit -= 2 * tree[n];//先走完当前所在的走廊,减去花费的时间,得到真正的时限

	//记忆搜索
	if (dp[n][time_limit] != 0)
		return dp[n][time_limit];

	//剪枝
	if (time_limit < 5)
		return 0;

	//若n尽头为房间
	if (tree[2 * n + 1] == 0)
	{
		dp[n][time_limit] = min(time_limit / 5, tree[2 * n]);//拿画的数量
		return dp[n][time_limit];
	}

	//否则 n 是个没搜过的、有分叉口的走廊
	int res = 0;//记录最多能拿到的画数量
	int time = 0;
	int choose = 0;
	//枚举自己把当前时限分配给两个岔路的所有情况,得到最优情况。分配本身就是dfs!
	for (int i = 0; i <= time_limit; i++)
	{
		//i为分配给左岔路2*n的时间,time_limit则是给右岔路2*i+1的
		int l_res = dfs(2 * n, i);
		int r_res = dfs(2 * n + 1, time_limit - i);
		if (res < l_res + r_res)
		{
			res = l_res + r_res;
			choose = i;
		}
		//res = ( (res < l_res + r_res) ? l_res + r_res : res);//记录在有限时间内获得最多画的方案
		
	}
	//cout << n<<" choose:"<<choose << endl;
	dp[n][time_limit] = res;
	return res;
}

int main()
{
	cin >> limit;//限时
	int time, volume, count=1;
	while (cin>>time>>volume)
	{
		tree[count] = time;
		if(volume==0)//走廊i的末端是分叉口
			count *= 2;//开始记录走廊2*i的信息
		else//这个数不为0说明找到了房间
		{
			tree[count * 2] = volume;
			tree[count * 2 + 1] = 0;
			while (count % 2)//奇数则回退到首个有右兄弟节点的父节点
				count /= 2;
			count++;//若count是偶数则count++(处理右兄弟节点走廊)
		}
	}
	cout << dfs(1, limit-1);
}
自认为可能存在的问题

1. 没有很严格地建个树,选择直接用2*n和2*n+1这样的方式建立父子结点关系;

2. 没有在输入时直接一并处理,而是在输入后重新走一遍

3. 对于dp数组的大小没有好好把控,导致最后一个样例RE了(内存溢出);但是再调大就不礼貌了(?)

但是嘞,在这一天反反复复修改的过程中,我把两次下载测试数据的机会都用掉了……所以今天摆烂!明天下载了再看看到底是什么原因。

也蹲蹲dp大神指点

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值