乘电梯还是走楼梯
2009-09-30 13:32
267 查看
http://acm.zjgsu.edu.cn/JudgeOnline.html
Description
blue 新开了一家公司,开张第一天,他邀请ACMers一起去玩。ACMers一定吓了一大跳,因为大厦有31层高。
所以大厦里肯定有电梯。每个ACMer都有自己想去的楼层,现在blue想,这些人要从大厦底层到达各自的目标楼层,
可以通过搭乘电梯,也可以走楼梯,每种方式都有固定的上楼所需时间,而电梯在每层停靠的时间也是固定的。
现在blue希望ACMers想出一个最佳的上楼方案,使得最后一个到达其目标楼层的人所花的时间最小。
现在规定:大厦有31层楼,乘电梯上(下)一楼要花4秒时间,电梯停靠需要花10秒时间,走楼梯上(下)
一楼需要花20秒时间。那么从1楼到31楼,如果乘电梯并且不停靠需要花(31-1)×4=120秒时间,如果每层都
停需要花30×4+29×10=410秒时间(在31楼没有必要停靠了),如果走楼梯的话需要花30×20=600秒时间。
假设ACMers需要在4,5,10楼停靠。那么最佳停靠方案为电梯在4,10楼停靠。因为电梯在4楼停靠需要花3×4
=12秒,然后停靠花费10秒,然后到达10楼需要花费3×4+10+6×4=46秒。那些想去4楼的ACMers需要花费12秒,那些
想去5楼的ACMers需要花费12+20=32秒,那些想去10楼的ACMers需要花费46秒。因此最后一个到达他的目标楼层最小
花费46秒。
Input
测试包括多组数据。
每组测试数据为一行,形如:n,f1,f2,f3,...fn (n<=30,2<=f1,f2,...,fn<=31)。
n代表总共有n楼电梯需要停靠,f1,f2,...fn是这些要停靠的楼层。
当n输入为0时结束。
Output
对应每组测试数据,输出一行,最后一个ACMer到达其目标层的最少时间。
Sample Input
Sample Output
有动态规划的代码但是看不懂,在另外一本书上看到是二分枚举加贪心,核心就两个公式,很像分形,还是看不懂。
照着贪心的思想自己写了一个,一直WA到凌晨,第二天吃中饭的时候终于发现犯了一个低级错误,终于。。。
再回过头来看那两个公式,原来就是把我的代码最简化.
这是书上的代码
用<=通过累加算边界时,可以用/代替,
终于弄懂动态规划的解法了。
Description
blue 新开了一家公司,开张第一天,他邀请ACMers一起去玩。ACMers一定吓了一大跳,因为大厦有31层高。
所以大厦里肯定有电梯。每个ACMer都有自己想去的楼层,现在blue想,这些人要从大厦底层到达各自的目标楼层,
可以通过搭乘电梯,也可以走楼梯,每种方式都有固定的上楼所需时间,而电梯在每层停靠的时间也是固定的。
现在blue希望ACMers想出一个最佳的上楼方案,使得最后一个到达其目标楼层的人所花的时间最小。
现在规定:大厦有31层楼,乘电梯上(下)一楼要花4秒时间,电梯停靠需要花10秒时间,走楼梯上(下)
一楼需要花20秒时间。那么从1楼到31楼,如果乘电梯并且不停靠需要花(31-1)×4=120秒时间,如果每层都
停需要花30×4+29×10=410秒时间(在31楼没有必要停靠了),如果走楼梯的话需要花30×20=600秒时间。
假设ACMers需要在4,5,10楼停靠。那么最佳停靠方案为电梯在4,10楼停靠。因为电梯在4楼停靠需要花3×4
=12秒,然后停靠花费10秒,然后到达10楼需要花费3×4+10+6×4=46秒。那些想去4楼的ACMers需要花费12秒,那些
想去5楼的ACMers需要花费12+20=32秒,那些想去10楼的ACMers需要花费46秒。因此最后一个到达他的目标楼层最小
花费46秒。
Input
测试包括多组数据。
每组测试数据为一行,形如:n,f1,f2,f3,...fn (n<=30,2<=f1,f2,...,fn<=31)。
n代表总共有n楼电梯需要停靠,f1,f2,...fn是这些要停靠的楼层。
当n输入为0时结束。
Output
对应每组测试数据,输出一行,最后一个ACMer到达其目标层的最少时间。
Sample Input
3 4 5 10 1 2 0
Sample Output
46 4
有动态规划的代码但是看不懂,在另外一本书上看到是二分枚举加贪心,核心就两个公式,很像分形,还是看不懂。
照着贪心的思想自己写了一个,一直WA到凌晨,第二天吃中饭的时候终于发现犯了一个低级错误,终于。。。
再回过头来看那两个公式,原来就是把我的代码最简化.
#include <iostream> #define MAXN 30001 using namespace std ; int a[MAXN] , n ; int Cmp (const void *e1 , const void *e2) { return *(int *)e1 - *(int *)e2 ; } bool Solved (int t) { int i , j , stops ; for (i = 0 ; i < n && (a[i] - 1) * 20 <= t ; i ++) ; for (stops = 0 , j = 1 ; i < n ; stops ++) { if ((a[i] - 1) * 4 + stops * 10 > t) return false ; for (j = a[i] ; j <= a[n - 1] && (j - a[i]) * 20 + (j - 1) * 4 + 10 * stops <= t ;) j ++ ; if (j > a[n - 1]) break ; j -- ; while (i < n && (a[i] - j) * 20 + (j - 1) * 4 + 10 * stops <= t) i ++ ; if (i == n) break ; } return true ; } int main () { int ans , low , i , high , mid ; while (scanf ("%d" , &n) , n) { memset (a , 0 , sizeof (a)) ; for (i = 0 ; i < n ; i ++) scanf ("%d" , &a[i]) ; qsort (a , n , sizeof (int) , Cmp) ; low = 0 ; high = 10000 ; while (low <= high) { mid = (low + high) >> 1 ; if (Solved (mid)) { ans = mid ; high = mid - 1 ; } else low = mid + 1 ; } printf ("%d/n" , ans) ; } return 0 ; }
这是书上的代码
#include <iostream> #define MAXN 40 using namespace std ; int a[MAXN] , n , bound ; bool Solved (int t) { int i , j , stops ; i = t / 20 + 2 ; for (stops = 0 ; i <= bound ; stops ++) { while (i <= bound && !a[i]) i ++ ; if ((i - 1) * 4 + stops * 10 > t) return false ; j = (t - 10 * stops + 20 * i + 4) / 24 ; //这个代码对应着我的第一个循环,在t的范围内,j表示要停的最高层数 i = (t - 10 * stops + 16 * j + 4) / 20 + 1 ; //这个代码对应着我的第二个循环,在j层停后,第i层以下都能在t的范围内达到目标层数 } return true ; } int main () { int ans , low , i , high , mid , tmp ; while (scanf ("%d" , &n) , n) { memset (a , 0 , sizeof (a)) ; for (i = bound = 0 ; i < n ; i ++) { scanf ("%d" , &tmp) ; if (tmp > bound) bound = tmp ; a[tmp] = 1 ; } low = 0 ; high = 1000 ; while (low <= high)//二分枚举答案 { mid = (low + high) >> 1 ; if (Solved (mid)) { ans = mid ; high = mid - 1 ; } else low = mid + 1 ; } printf ("%d/n" , ans) ; } return 0 ; }
用<=通过累加算边界时,可以用/代替,
终于弄懂动态规划的解法了。
#include <iostream> #include <algorithm> #define INF 1000 using namespace std ; int max (int a , int b) { return a > b ? a : b ; } int min (int a , int b) { return a < b ? a : b ; } int main () { int f[35][35] , a[35] , i , j , k , walk , stops , n ; while (scanf ("%d" , &n) , n) { for (i = 0 ; i < n ; i ++) scanf ("%d" , &a[i]) ; sort (a , a + n) ; for (i = 0 ; i < 35 ; i ++) for (j = 0 ; j < 35 ; j ++) f[i][j] = INF ; for (i = a[n - 1] ; i > 0 ; i --) for (j = n - 1 ; j >= 0 ; j --) { f[i][j] = f[i + 1][j] + 4 ; for (walk = 0 , k = j ; k < n ; k ++) { walk = max (walk , 20 * abs (a[k] - i)) ; if (k < n - 1) { stops = (i > 1 ? 10 : 0) ; f[i][j] = min (f[i][j] , max (f[i + 1][k + 1] + stops + 4 , walk)) ; } else f[i][j] = min (f[i][j] , walk) ; } } printf ("%d/n" , f[1][0]) ; } return 0 ; }
相关文章推荐
- 上楼一次走一节还是两节楼梯,走法计算思路
- 终于还是变了
- 【ASP.NET 进阶】判断访问网站的客户端是PC还是手机
- 递归--走楼梯
- Google招聘的21道题目—考智慧还是考灵气
- 结对开发:电梯调度(2)
- 判断viewController是否被push,返回上一页dismiss还是pop
- 确定Windows XP到底是UCS-2的还是UTF-16的
- hdu 2600 War(贪心)题目不难,比赛的时候还是错了一遍
- 程序选用多字节还是Unicode建
- 独家评论:就业还是创业 大学生首先应学会敬业
- 职场经:你是千里马还是一头驴?
- js判断请求是http还是https
- 缓冲还是不缓冲?这是个问题
- 如何看linux是32位还是64位
- [JAVA]好的电梯程序的设计
- ios判断设备是iphone还是ipad
- HDU1180-诡异的楼梯(bfs)
- 电梯控制模拟代码简析(MFC)