【CF983C】elevator——记忆化搜索
(题面来自luogu)
题意翻译
题意
一个9层的楼有一个可以容纳4个人的电梯,你要管理这个电梯。
现在各层楼上有一些在排队的人,你知道他们在哪层要到哪层去。你也知道到电梯门口的顺序。根据公司的规定,如果一个人比其他人早到。他也必须先进电梯(无论楼层,只凭时间)。注意人们可以随时离开电梯。
电梯有两个命令:
- 上楼或者下楼, 代价为1
- 打开当前楼层的门,所有到目的地的人会从电梯里出来,当前楼层排队的人会在不违反规定的情况下一个一个进(在电梯还有空间的情况下)(这不是天朝的电梯,不能超员)每个人用1s时间来出入电梯。
最初电梯是空的,在1楼。你需要求出最少用多长时间来吧所有人送回到目的地。最后电梯可以停在任意位置
输入输出格式:
输入格式
- 第一行一个整数n : 人的数量
- 下面n行给出每个人的起点、终点。
输出格式
- 一个整数表示以秒为单位的最小时间
数据范围:人数小于等于2000。
----------------------------------------------------------------------------------
不知道从哪里搞来的这么偏门的考试题……一道很恶心的状压DP,需要压缩的状态是当前电梯内四个人要去的楼层。在设计状态时,要尽可能简化题目中的信息,只抽出那些真正可能影响答案的本质。
由于人是按次序上电梯的,我们只能按编号逐个处理,这一维的转移结构也就确定了。紧接着设计了当前电梯的运行状态这一信息:假设处理时电梯从底下上行而来,回到电梯来的楼层显然会重复状态,是不会更优的。第三维记录电梯所在楼层,第四维则是当前电梯内几个人要去的楼层,0表示空位。这个状态用map压起来,用康托展开也是可以的。
那么每次对于每个状态,如果电梯有人可以下或者下一个要处理的人刚好在这一层,我们就让电梯停下来,贪心地把这些事处理完,再来考虑运行。现在如果电梯停着,我们就让它上下动动;如果正在运行,我们就让它继续沿着当前方向运行,保证不会重复。
代码:
- #include <cstdio>
- #include <iostream>
- #include <cstring>
- #include <algorithm>
- #include <map>
- #include <vector>
- #define mp make_pair
- #define st first
- #define dst second
- using namespace std;
- void open_file(string s) {
- string In = s + ".in", Out = s + ".out";
- freopen(In.c_str(), "r", stdin);
- freopen(Out.c_str(), "w", stdout);
- }
- int f[2010][3][9][715], n;//第一维当前处理人数,第二维运行方向,第三维楼层(0~8),第四维当前装载状态
- map<vector<int>, int> M;
- vector<int> load[715];
- pair<int, int> p[2010];
- bool cmp(int a, int b) {
- return a > b;
- }
- int dfs(int cur, int op, int fl, int key) {
- if (cur == n + 1 && key == 0)
- return 0;
- if (fl == -1 || fl == 9)
- return (int)1e9;
- if (f[cur][op][fl][key])
- return f[cur][op][fl][key];
- int &ans = f[cur][op][fl][key];
- vector<int> tmp = load[key];
- int lv = 0;
- for (int i = 0; i < (int)tmp.size(); ++i)
- if (tmp[i] == fl + 1)
- tmp[i]= 0, ++lv;
- if (lv) {//先下完
- sort(tmp.begin(), tmp.end(), cmp);
- return dfs(cur, 0, fl, M[tmp]) + lv;
- }
- if (cur <= n && p[cur].st == fl + 1 && tmp[3] == 0) {//再来上人
- tmp[3] = p[cur].dst;
- sort(tmp.begin(), tmp.end(), cmp);
- return ans = dfs(cur + 1, 0, fl, M[tmp]) + 1;
- }
- //接下来是啥也没拉到的情况
- if (op == 0) //停着就上下动动
- return ans = min(dfs(cur, 1, fl + 1, key), dfs(cur, 2, fl - 1, key)) + 1;
- else if (op == 1) //继续往上
- return ans = dfs(cur, 1, fl + 1, key) + 1;
- else
- return ans = dfs(cur, 2, fl - 1, key) + 1;
- }
- int main() {
- open_file("elevator");
- ios::sync_with_stdio(0);
- int cnt = -1;
- for (int i = 0; i <= 9; ++i) // 降序排列
- for (int j = 0; j <= i; ++j)
- for (int k = 0; k <= j; ++k)
- for (int h = 0; h <= k; ++h) {
- load[++cnt].push_back(i);
- load[cnt].push_back(j);
- load[cnt].push_back(k);
- load[cnt].push_back(h);
- M[load[cnt]] = cnt;
- // puts("%");
- }
- // cout << cnt;//最多715种状态
- cin >> n;
- for (int i = 1; i <= n; ++i)
- cin >> p[i].st >> p[i].dst;
- cout << dfs(1, 1, 0, 0) << endl;
- return 0;
- }
我感觉这题只能搜索,因为不知道电梯会在哪里停下,递推转移可能会很麻烦。(欢迎推翻这个flag)
【CF983C】elevator——记忆化搜索的更多相关文章
- [ACM_动态规划] 数字三角形(数塔)_递推_记忆化搜索
1.直接用递归函数计算状态转移方程,效率十分低下,可以考虑用递推方法,其实就是“正着推导,逆着计算” #include<iostream> #include<algorithm> ...
- 【BZOJ-3895】取石子 记忆化搜索 + 博弈
3895: 取石子 Time Limit: 1 Sec Memory Limit: 512 MBSubmit: 263 Solved: 127[Submit][Status][Discuss] D ...
- hdu3555 Bomb (记忆化搜索 数位DP)
http://acm.hdu.edu.cn/showproblem.php?pid=3555 Bomb Time Limit: 2000/1000 MS (Java/Others) Memory ...
- zoj 3644(dp + 记忆化搜索)
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4834 思路:dp[i][j]表示当前节点在i,分数为j的路径条数,从 ...
- loj 1044(dp+记忆化搜索)
题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=26764 思路:dp[pos]表示0-pos这段字符串最少分割的回文 ...
- DP(记忆化搜索) + AC自动机 LA 4126 Password Suspects
题目传送门 题意:训练指南P250 分析:DFS记忆化搜索,范围或者说是图是已知的字串构成的自动机图,那么用 | (1 << i)表示包含第i个字串,如果长度为len,且st == (1 ...
- HDU1978 记忆化搜索
How many ways Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Tot ...
- bzoj4562: [Haoi2016]食物链--记忆化搜索
这道题其实比较水,半个小时AC= =对于我这样的渣渣来说真是极大的鼓舞 题目大意:给出一个有向图,求入度为0的点到出度为0的点一共有多少条路 从入读为零的点进行记忆化搜索,搜到出度为零的点返回1 所有 ...
- 数位dp/记忆化搜索
一.引例 #1033 : 交错和 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个数 x,设它十进制展从高位到低位上的数位依次是 a0, a1, ..., an ...
随机推荐
- 深入理解Java注解类型(@Annotation)
http://blog.csdn.net/javazejian/article/details/71860633 出自[zejian的博客] java注解是在JDK5时引入的新特性,鉴于目前大部分框 ...
- 操作安装docker
在本地建造起vue-cli服务 参考项目:https : //gitee.com/QiHanXiBei/myvue 在本地建造起一个django项目架构,通过/ hello能够打印出helloworl ...
- STM32入门系列-GPIO概念介绍
GPIO(general purpose intput output)是通用输入输出端口的简称,可以通过软件来控制其输入和输出.STM32 芯片的 GPIO 引脚与外部设备连接起来,从而实现与外部通讯 ...
- 03 . Gin+Vue开发一个线上外卖应用(用户数据创建,插入,跨域处理)
功能和背景介绍 在项目的登录功能中,如果在登录时发现用户名和密码在用户表中不存在,会自动将用户名和密码保存在用户表中,创建一个新的用户. 因此,除了使用手机号和验证码登录以外,还支持使用用户名.密码进 ...
- Redis发布订阅使用方法
Redis发布订阅 发布订阅模式中发布消息的为publisher即发布者,接收消息的为subscriber即订阅者.在Redis中,所有的消息通过channel即频道进行发布,一个发布者可以向多个ch ...
- SQL SERVER级联查询及数据结构《存储过程-递归树形查询》
--创建表,插入数据 create table tb(id varchar(3) , pid varchar(3) , name varchar(10))insert into tb values(' ...
- 利用sklearn实现k-means
基于上面的一篇博客k-means利用sklearn实现k-means #!/usr/bin/env python # coding: utf-8 # In[1]: import numpy as np ...
- 剑指Offer-Python(1-5)
1.二维数组的查找 查找,其实就可以挨个进行比较就可以.又由于题目说明(每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序),因此如果利用类似于二分查找的方法,那么比较次数则会更少 ...
- [.Net Core 3.0+/.Net 5] System.Text.Json中时间格式化
简介 .Net Core 3.0开始全新推出了一个名为System.Text.Json的Json解析库,用于序列化和反序列化Json,此库的设计是为了取代Json.Net(Newtonsoft.Jso ...
- 解决js中对象中属性是数组中对应元素,不能使用点数组元素(.数组[i])来获取value值来循环,属性不能是数组元素array[i]的问题
数据类型 //示例 var tags1avg= ['rg2_crt_001_001_avg', 'rg2_crt_001_002_avg', 'rg2_crt_001_003_avg', 'rg2_c ...