POJ1083-Moving Tables

来源:http://exp-blog.com/2018/06/14/pid-269/

提示:利用房间号分割走廊,每条“子走廊”都设置一个计数器,每经过一次+1,完了最后对计数器快排,最大的次数X10就是答案

初看此题有点像贪心的感觉,因为可能会想到把输入的搬运区间的交点(临界点)进行统计,这是很笨很没效率的方法,而且要考虑一堆可能情况,我按这个思路用栈做过这题,列出了所有可能的例子,结果一致但无限WA。。。。所以呼吁大众:不要误入歧途了。。。

 

  1. /*
  2. Author: Exp
  3. Date: 2017-11-30
  4. Code: POJ 1083
  5. Problem: Moving Tables
  6. URL: http://poj.org/problem?id=1083
  7. */
  8. /*
  9. 题意分析:
  10. 酒店有400个房间,如下编号对称分布在一条走廊两侧
  11. 1 3 5 ... 397 399
  12. 这里是走廊
  13. 2 4 6 ... 398 400
  14. 现在要从房间s->t搬桌子,有N组房间需要搬桌子,每搬一次10分钟(不论两个房间相隔多远).
  15. 对于某组房间,搬桌子期间 s->t 之间的走廊会被占用,
  16. 而其他组房间若没有使用到占用的走廊,则可同时搬,否则要等待.
  17. 特别地,相对的两间房,共用一段走廊, 即若房间3的走廊被占用了,等同于房间4的走廊被占用了.
  18. 给定N组需要搬的桌子,求最小可以搬完的时间.
  19. 解题思路:
  20. 感觉这题有点类似于多线程的同步互斥场景问题.
  21. ① 由于相对的两间房共用同一段走廊,为了方便处理问题,可以把所有奇数房间转换成偶数房间,反之亦可.
  22. 如 1->6 可等价转换成 2->6, 尔后只需要关注一侧的房间即可(共200间)
  23. ② 根据房间号对走廊进行分割,可分割成200段走廊. 在从房间s->t搬桌子期间,对所使用到的每段走廊计数+1
  24. ③ 所有桌子搬完后,统计每段走廊的计数值(计数值代表这段走廊总共需要被占用的次数),
  25. 由于题目并不考虑搬动期间的移动过程因素(类比多线程的事务锁),
  26. 因此最大的一个计数值*10分钟 就是所求的最小搬完时间(因为只要走廊被占着,就只能在下一次再搬,不能同时搬)
  27. */
  28. #include <iostream>
  29. using namespace std;
  30. const static int ROOM_NUM = 400; // 最大房号
  31. const static int TIME_UNIT = 10; // 时间单位
  32. /*
  33. * 把偶数房号转换成奇数房号
  34. * @param even 偶数房号
  35. * return 奇数房号
  36. */
  37. int toOdd(int even);
  38. /*
  39. * 问题求解
  40. */
  41. void solve(void);
  42. int main(void) {
  43. int testCase = 0;
  44. cin >> testCase;
  45. for( int t = 0; t < testCase; t++) {
  46. solve();
  47. }
  48. //system("pause");
  49. return 0;
  50. }
  51. int toOdd(int even) {
  52. return (even % 2 == 0 ? even - 1 : even);
  53. }
  54. void solve(void) {
  55. int useCnt[ROOM_NUM] = { 0 }; // 每个房间前的走廊被使用的次数
  56. int maxUseCnt = 0; // 被使用最多的次数
  57. int moveCnt = 0; // 需要搬动的桌子组数
  58. cin >> moveCnt;
  59. int* fromRooms = new int[moveCnt]; // 起点房间集
  60. int* toRooms = new int[moveCnt]; // 终点房间集
  61. for( int i = 0; i < moveCnt; i++) {
  62. int from, to;
  63. cin >> from >> to;
  64. // 使房号小的在前面
  65. fromRooms[i] = (from <= to ? from : to);
  66. toRooms[i] = (from > to ? from : to);
  67. // 把房号全部转换成奇数
  68. fromRooms[i] = toOdd(fromRooms[i]);
  69. toRooms[i] = toOdd(toRooms[i]);
  70. // 相关房间前占用的走廊被使用次数+1
  71. for( int roomId = fromRooms[i]; roomId <= toRooms[i]; roomId += 2) {
  72. useCnt[roomId]++;
  73. if(maxUseCnt < useCnt[roomId]) {
  74. maxUseCnt = useCnt[roomId]; // 登记最大的使用次数
  75. }
  76. }
  77. }
  78. delete[] fromRooms;
  79. delete[] toRooms;
  80. // 计算最小的使用时间
  81. maxUseCnt = (maxUseCnt <= 0 || maxUseCnt > moveCnt ? moveCnt : maxUseCnt);
  82. int minUsedTime = maxUseCnt * TIME_UNIT;
  83. cout << minUsedTime << endl;
  84. }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值