(题面来自luogu)

题意翻译

题意

一个9层的楼有一个可以容纳4个人的电梯,你要管理这个电梯。

现在各层楼上有一些在排队的人,你知道他们在哪层要到哪层去。你也知道到电梯门口的顺序。根据公司的规定,如果一个人比其他人早到。他也必须先进电梯(无论楼层,只凭时间)。注意人们可以随时离开电梯。

电梯有两个命令:

  • 上楼或者下楼, 代价为1
  • 打开当前楼层的门,所有到目的地的人会从电梯里出来,当前楼层排队的人会在不违反规定的情况下一个一个进(在电梯还有空间的情况下)(这不是天朝的电梯,不能超员)每个人用1s时间来出入电梯。

最初电梯是空的,在1楼。你需要求出最少用多长时间来吧所有人送回到目的地。最后电梯可以停在任意位置

输入输出格式:

输入格式

  • 第一行一个整数n : 人的数量
  • 下面n行给出每个人的起点、终点。

    输出格式

  • 一个整数表示以秒为单位的最小时间

数据范围:人数小于等于2000。

----------------------------------------------------------------------------------

  不知道从哪里搞来的这么偏门的考试题……一道很恶心的状压DP,需要压缩的状态是当前电梯内四个人要去的楼层。在设计状态时,要尽可能简化题目中的信息,只抽出那些真正可能影响答案的本质。

  由于人是按次序上电梯的,我们只能按编号逐个处理,这一维的转移结构也就确定了。紧接着设计了当前电梯的运行状态这一信息:假设处理时电梯从底下上行而来,回到电梯来的楼层显然会重复状态,是不会更优的。第三维记录电梯所在楼层,第四维则是当前电梯内几个人要去的楼层,0表示空位。这个状态用map压起来,用康托展开也是可以的。

  那么每次对于每个状态,如果电梯有人可以下或者下一个要处理的人刚好在这一层,我们就让电梯停下来,贪心地把这些事处理完,再来考虑运行。现在如果电梯停着,我们就让它上下动动;如果正在运行,我们就让它继续沿着当前方向运行,保证不会重复。

代码:

  1. #include <cstdio>
  2. #include <iostream>
  3. #include <cstring>
  4. #include <algorithm>
  5. #include <map>
  6. #include <vector>
  7. #define mp make_pair
  8. #define st first
  9. #define dst second
  10. using namespace std;
  11. void open_file(string s) {
  12. string In = s + ".in", Out = s + ".out";
  13. freopen(In.c_str(), "r", stdin);
  14. freopen(Out.c_str(), "w", stdout);
  15. }
  16. int f[2010][3][9][715], n;//第一维当前处理人数,第二维运行方向,第三维楼层(0~8),第四维当前装载状态
  17. map<vector<int>, int> M;
  18. vector<int> load[715];
  19. pair<int, int> p[2010];
  20. bool cmp(int a, int b) {
  21. return a > b;
  22. }
  23. int dfs(int cur, int op, int fl, int key) {
  24. if (cur == n + 1 && key == 0)
  25. return 0;
  26. if (fl == -1 || fl == 9)
  27. return (int)1e9;
  28. if (f[cur][op][fl][key])
  29. return f[cur][op][fl][key];
  30. int &ans = f[cur][op][fl][key];
  31. vector<int> tmp = load[key];
  32. int lv = 0;
  33. for (int i = 0; i < (int)tmp.size(); ++i)
  34. if (tmp[i] == fl + 1)
  35. tmp[i]= 0, ++lv;
  36. if (lv) {//先下完
  37. sort(tmp.begin(), tmp.end(), cmp);
  38. return dfs(cur, 0, fl, M[tmp]) + lv;
  39. }
  40. if (cur <= n && p[cur].st == fl + 1 && tmp[3] == 0) {//再来上人
  41. tmp[3] = p[cur].dst;
  42. sort(tmp.begin(), tmp.end(), cmp);
  43. return ans = dfs(cur + 1, 0, fl, M[tmp]) + 1;
  44. }
  45. //接下来是啥也没拉到的情况
  46. if (op == 0)  //停着就上下动动
  47. return ans = min(dfs(cur, 1, fl + 1, key), dfs(cur, 2, fl - 1, key)) + 1;
  48. else if (op == 1) //继续往上
  49. return ans = dfs(cur, 1, fl + 1, key) + 1;
  50. else
  51. return ans = dfs(cur, 2, fl - 1, key) + 1;
  52. }
  53. int main() {
  54. open_file("elevator");
  55. ios::sync_with_stdio(0);
  56. int cnt = -1;
  57. for (int i = 0; i <= 9; ++i) // 降序排列
  58. for (int j = 0; j <= i; ++j)
  59. for (int k = 0; k <= j; ++k)
  60. for (int h = 0; h <= k; ++h) {
  61. load[++cnt].push_back(i);
  62. load[cnt].push_back(j);
  63. load[cnt].push_back(k);
  64. load[cnt].push_back(h);
  65. M[load[cnt]] = cnt;
  66. //                  puts("%");
  67. }
  68. //  cout << cnt;//最多715种状态
  69. cin >> n;
  70. for (int i = 1; i <= n; ++i)
  71. cin >> p[i].st >> p[i].dst;
  72. cout << dfs(1, 1, 0, 0) << endl;
  73. return 0;
  74. }

  我感觉这题只能搜索,因为不知道电梯会在哪里停下,递推转移可能会很麻烦。(欢迎推翻这个flag)

【CF983C】elevator——记忆化搜索的更多相关文章

  1. [ACM_动态规划] 数字三角形(数塔)_递推_记忆化搜索

    1.直接用递归函数计算状态转移方程,效率十分低下,可以考虑用递推方法,其实就是“正着推导,逆着计算” #include<iostream> #include<algorithm> ...

  2. 【BZOJ-3895】取石子 记忆化搜索 + 博弈

    3895: 取石子 Time Limit: 1 Sec  Memory Limit: 512 MBSubmit: 263  Solved: 127[Submit][Status][Discuss] D ...

  3. hdu3555 Bomb (记忆化搜索 数位DP)

    http://acm.hdu.edu.cn/showproblem.php?pid=3555 Bomb Time Limit: 2000/1000 MS (Java/Others)    Memory ...

  4. zoj 3644(dp + 记忆化搜索)

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4834 思路:dp[i][j]表示当前节点在i,分数为j的路径条数,从 ...

  5. loj 1044(dp+记忆化搜索)

    题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=26764 思路:dp[pos]表示0-pos这段字符串最少分割的回文 ...

  6. DP(记忆化搜索) + AC自动机 LA 4126 Password Suspects

    题目传送门 题意:训练指南P250 分析:DFS记忆化搜索,范围或者说是图是已知的字串构成的自动机图,那么用 | (1 << i)表示包含第i个字串,如果长度为len,且st == (1 ...

  7. HDU1978 记忆化搜索

    How many ways Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tot ...

  8. bzoj4562: [Haoi2016]食物链--记忆化搜索

    这道题其实比较水,半个小时AC= =对于我这样的渣渣来说真是极大的鼓舞 题目大意:给出一个有向图,求入度为0的点到出度为0的点一共有多少条路 从入读为零的点进行记忆化搜索,搜到出度为零的点返回1 所有 ...

  9. 数位dp/记忆化搜索

    一.引例 #1033 : 交错和 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个数 x,设它十进制展从高位到低位上的数位依次是 a0, a1, ..., an  ...

随机推荐

  1. Jenkins配置,tomacat版本输出乱码和页面打开报404的问题

    1.打开tomact下的startup.bat,tomcat版本控制台中文输出乱码,解决方法是去tomacat安装路径下的conf目录,打开logging.properties文件,将java.uti ...

  2. equals()方法和hashCode()方法详解

    equals()方法和hashCode()方法详解 1. Object类中equals()方法源代码如下所示: /** * Object类中的equals()方法 */ public boolean ...

  3. JVM的艺术—类加载器篇(二)

    分享是价值的传递,喜欢就点个赞 引言 今天我们继续来深入的剖析类加载器的内容.上节课我们讲了类加载器的基本内容,没看过的小伙伴请加关注.今天我们继续. 什么是定义类加载器和初始化类加载器? 定义类加载 ...

  4. MySQL中没有FULL OUTER JOIN的处理

    FULL OUTER JOIN:SELECT column_name(s)FROM table1FULL OUTER JOIN table2ON table1.column_name=table2.c ...

  5. linux查看日志的几种方法

    linux 日志查看 tail.head. cat.tac.sed.less.echo 1.命令格式: tail       [必要参数]     [选择参数]     [文件] -f 循环读取 -q ...

  6. 排序算法—快速排序(Quick Sort)

    快速排序(Quick Sort) 快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序. ...

  7. 初次使用flask

    以写的一个小的例子来记录第一次使用: from flask import Flask, render_template import json # 实例化,可视为固定格式 app = Flask(__ ...

  8. 凝思磐石安全系统V6.0.8版本(debian)增加多于4个串口方法

    在网上找了好多方法,大家基本上都用ubuntu系统做实现演示,里面的有些文件我在凝思系统上根本找不到,最终通过摸索已解决,记录下操作过程(整个过程都需要在root用户下进行): 判断系统目前能识别的串 ...

  9. Firefox威武 尚译威武!

    有感于鹰文文档看起来麻烦,期待有一款即时翻译的工具,在windows上还可以,但是上班用的是ubuntu,所以就想到要找一个firefox插件,还真找到了,但是不是插件,是一个书签,那就是尚译!尚哥威 ...

  10. 企业网络拓扑RSTP功能实例

    组网图形  RSTP简介 以太网交换网络中为了进行链路备份,提高网络可靠性,通常会使用冗余链路.但是使用冗余链路会在交换网络上产生环路,引发广播风暴以及MAC地址表不稳定等故障现象,从而导致用户通信质 ...