hiho一下第六十五周HighWay--也属于动态规划吧
2015-09-30 21:30
225 查看
HighWay这一题描述如下:
给定一条高速公路,
在时间点为0时公路上停了N辆车,每辆车起始位置都不同,
首先输入一个整数N,2 <= N <= 1000.
接着输入N行,每一行格式为3个整数:X, Y and L,分别是一辆车的起始位置,离开位置以及速度。 0
<= X < Y <= 1000000, 0 < L <= 10.
因为高速公路只有一条车道,所以规定行驶在后面的车子不能超过行驶在它前面的车。
链接:http://hihocoder.com/contest/hiho65/problem/1
关于这题的解法,如果把它当做追及问题,就会变得非常非常复杂,我试了一下,感觉好像不是特别难,但是在写的时候遇到各种问题,真心不简单。
所以有大神提供了一种可以用动态规划来进行解决的思路:
http://hihocoder.com/discuss/question/2533
由此看来,按照每辆车的起始位置进行排序是个好想法,排序之后依照顺序从最前边的车子开始依次进行处理。
这个想法是大家都能想到的,我想到这个点子之后就继续往追及问题上考虑了,我首先思考了两辆车的追及情况,overtaking是否可能,如果发生了overtaking,后边的车子有哪些需要改变的呢?反正挺复杂的,写起来非常麻烦。
幸好大神提供了另一个点子,依然是根据每辆车都不能超过它前面的车这一个限制。
它告诉了我们什么呢?在公路上的某一个地点pos上,对于一辆车car1,如果它前面还有其他的车比如car2,car3,...,
那么car1通过pos的时间一定是要大于等于car2,car3它们通过pos的时间的!
分析一下:
假设car2便是car1正前方的车,
如果car1能追上car2,并且在overtakingPos追上,那么在追上之前的这段路程car1->start到overtakingPos上car1到达的时间很明显是大于car2的,
在追上之后的路程上因为car1不能超过car2,所以它们经过这段路的时间是一样的。
如果car1不能追上car2,那么在car1的全程路段很明显它到达的时间是要大于car2的。
所以我们需要维护的是在公路上任一点pos上车子到达它所需的最大时间。
按照动态规划的方式来做的话,我的思路大致如下:
首先用类RunningCar来记录车的状态
接着为了解决问题,定义如下几个变量:
vector<int> startPoints,按照输入顺序记录各辆车起始点位置
vector<int> sortedStarts,对startPoints进行排序后的结果
map<int, RunningCar *> runningCars根据每辆车的起始点映射该辆车的结构,因为每辆车的起始位置都不同,所以正好用起始位置作为标记
int maxEnd,在输入过程中不断更新,记录所有车中最大的离开位置
double *maxArrivingTime,动态规划的核心了,我们是从sortedStarts的最后开始向前处理,记录当前已通过车辆通过pos位置的最大离开时间
代码思路大致如下:
在具体实现的时候,因为最近在看《代码整洁之道》,所以做了如下设计:
整个问题设计为一个HighWay类。
整段代码如下:
1. 它已经overtaking前面的车,因为不能超车,所以它此时前面的车速度一样,经过pos的时间也一样,所以此时时间为maxArrivingTime[pos]。
2. 如果它没有超车,那么用maxArrivingTime[pos-1]再加上跑1单位距离所需要的时间即可,
因为pos是从curCar->start+1开始的,当pos = start+1时,maxArrivingTime[pos-1]必然为0;
而当pos > start +1时,pos位置可能是前面的车已经跑的地方,所以此时有两种可能,一种是前面的车已经跑完了,所以本车恢复原速度继续跑,还有一种是pos位置只有curCar跑过,不管是哪种情况,curCar经过pos-1位置时的时间都是maxArrivingTime[pos-1],而接着它是以curCar->speed速度跑,所以很轻易就能计算出它跑过pos的时间。
3. 最后取这两种时间的最大值即可。
我定义HighWay类,它里边有个成员变量为double *maxArrivingTime,
我在构造函数里边将它初始化为NULL。
接着在void readDataAndInitialize()函数里边我是为它分配空间并进行初始化,
当时写成了double *maxArrivingTime = new double[maxEnd+1];
for (int i = 0; i < maxEnd+1; i++)
maxArrivingTime[i] = 0;
这样就出错了,同名变量的问题,C++编译的时候不会提示错误,但运行的时候却是会出错的!
2.用示例是可以运行成功,但还是得自己也设计几个例子来测试下
比如如下运行示例:
我发现出问题了,所以用isDebug进行信息输出,原来是我最后输出结果的时候出了问题
给定一条高速公路,
在时间点为0时公路上停了N辆车,每辆车起始位置都不同,
首先输入一个整数N,2 <= N <= 1000.
接着输入N行,每一行格式为3个整数:X, Y and L,分别是一辆车的起始位置,离开位置以及速度。 0
<= X < Y <= 1000000, 0 < L <= 10.
因为高速公路只有一条车道,所以规定行驶在后面的车子不能超过行驶在它前面的车。
链接:http://hihocoder.com/contest/hiho65/problem/1
关于这题的解法,如果把它当做追及问题,就会变得非常非常复杂,我试了一下,感觉好像不是特别难,但是在写的时候遇到各种问题,真心不简单。
所以有大神提供了一种可以用动态规划来进行解决的思路:
http://hihocoder.com/discuss/question/2533
思路
这一题的关键在于每辆车都不能超过它前面的车,所以最前面的车它可以按照自己的速度跑完,第二前的车只会受到最前面车的影响,。。。。。由此看来,按照每辆车的起始位置进行排序是个好想法,排序之后依照顺序从最前边的车子开始依次进行处理。
这个想法是大家都能想到的,我想到这个点子之后就继续往追及问题上考虑了,我首先思考了两辆车的追及情况,overtaking是否可能,如果发生了overtaking,后边的车子有哪些需要改变的呢?反正挺复杂的,写起来非常麻烦。
幸好大神提供了另一个点子,依然是根据每辆车都不能超过它前面的车这一个限制。
它告诉了我们什么呢?在公路上的某一个地点pos上,对于一辆车car1,如果它前面还有其他的车比如car2,car3,...,
那么car1通过pos的时间一定是要大于等于car2,car3它们通过pos的时间的!
分析一下:
假设car2便是car1正前方的车,
如果car1能追上car2,并且在overtakingPos追上,那么在追上之前的这段路程car1->start到overtakingPos上car1到达的时间很明显是大于car2的,
在追上之后的路程上因为car1不能超过car2,所以它们经过这段路的时间是一样的。
如果car1不能追上car2,那么在car1的全程路段很明显它到达的时间是要大于car2的。
所以我们需要维护的是在公路上任一点pos上车子到达它所需的最大时间。
按照动态规划的方式来做的话,我的思路大致如下:
首先用类RunningCar来记录车的状态
class RunningCar { double start; double end; double speed; double leavingTime; ... };
接着为了解决问题,定义如下几个变量:
vector<int> startPoints,按照输入顺序记录各辆车起始点位置
vector<int> sortedStarts,对startPoints进行排序后的结果
map<int, RunningCar *> runningCars根据每辆车的起始点映射该辆车的结构,因为每辆车的起始位置都不同,所以正好用起始位置作为标记
int maxEnd,在输入过程中不断更新,记录所有车中最大的离开位置
double *maxArrivingTime,动态规划的核心了,我们是从sortedStarts的最后开始向前处理,记录当前已通过车辆通过pos位置的最大离开时间
代码思路大致如下:
For startPoint in sortedStarts from the rear curCar = runningCars[startPoint]; For pos from curCar.start+1 to curCar.end timeWithNoOvertaking = maxArrivingTime[pos-1] + 1.0/curCar.speed; timeWithOvertaking = maxArrivingTime[pos]; maxArrivingTime[pos] = max( timeWithNoOvertaking, timeWithOvertaking); End for curCar.setLeavingTime(maxArrivingTime[curCar.end]); End for就上面这一小段,弄清楚了就很简单了。
在具体实现的时候,因为最近在看《代码整洁之道》,所以做了如下设计:
整个问题设计为一个HighWay类。
整段代码如下:
#include <iostream> #include <map> #include <vector> #include <algorithm> using namespace std; bool isDebug = true; class RunningCar { double start; double end; double speed; double leavingTime; public: RunningCar() { start = end = 0; speed = 0; } RunningCar(double start, double end, double speed) { this->start = start; this->end = end; this->speed = speed; } double getStart() { return start; } double getEnd() { return end; } double getSpeed() { return speed; } double getLeavingTime() { return leavingTime; } void setLeavingTime(double leavingTime) { this->leavingTime = leavingTime; } void display() { cout << "I am a car starts from " << start << " ends at " << end << " with the speed of " << speed << endl; } }; class HighWay { int N; int maxEnd; map<int, RunningCar *> runningCars; vector<int> startPoints; vector<int> sortedStarts; double *maxArrivingTime; public: HighWay() { maxEnd = 0; maxArrivingTime = NULL; } ~HighWay() { if (maxArrivingTime != NULL) { delete[] maxArrivingTime; maxArrivingTime = NULL; } runningCars.clear(); startPoints.clear(); sortedStarts.clear(); } void readDataAndInitialize() { cin >> N; for (int i = 0; i < N; i++) { int start, end, speed; cin >> start >> end >> speed; if (maxEnd < end) maxEnd = end; RunningCar *newCar = new RunningCar(start, end, speed); runningCars[start] = newCar; startPoints.push_back(start); } maxArrivingTime = new double[maxEnd+1]; for (int i = 0; i < maxEnd+1; i++) maxArrivingTime[i] = 0; sortedStarts = startPoints; sort(sortedStarts.begin(), sortedStarts.end()); } void calculateMaxLeavingTime() { int carsRunningAhead = sortedStarts.size(); while (carsRunningAhead > 0) { RunningCar *curCar = runningCars[sortedStarts[carsRunningAhead-1]]; calculateLeavingTimeForCar(curCar); carsRunningAhead--; } } private: void calculateLeavingTimeForCar(RunningCar *curCar) { for (int i = curCar->getStart()+1; i <= curCar->getEnd(); i++) { calculateLeavingTimeForCarInPos(curCar, i); } curCar->setLeavingTime(maxArrivingTime[(int)curCar->getEnd()]); if (isDebug) { printf("The car leaved at time %.2lf\n", curCar->getLeavingTime()); } } void calculateLeavingTimeForCarInPos(RunningCar *curCar, int pos) { double timeWithNoOvertaking = maxArrivingTime[pos-1] + 1.0/curCar->getSpeed(); maxArrivingTime[pos] = max(maxArrivingTime[pos], timeWithNoOvertaking); if (isDebug) { printf("The car starts from %.0lf, ends at %.0lf, current pos at %d, time is %.2lf\n", curCar->getStart(), curCar->getEnd(), pos, maxArrivingTime[pos]); } } public: void showMaxArrivingTime() { for (int i = 0; i < maxEnd+1; i++) { cout << "The "<< i << "th max arriving time is " << maxArrivingTime[i] << endl; } } void showLeavingTime() { for (int i = 0; i < startPoints.size(); i++) { RunningCar *curCar = runningCars[startPoints[i]]; //printf("%.2lf\n", maxArrivingTime[(int)curCar->getEnd()]); printf("%.2lf\n", curCar->getLeavingTime()); } } }; int main() { HighWay highWay; highWay.readDataAndInitialize(); highWay.calculateMaxLeavingTime(); //highWay.calculateLeavingTimeForCar(NULL); if (isDebug) highWay.showMaxArrivingTime(); highWay.showLeavingTime(); system("pause"); return 0; }
计算某车在pos位置时的离开时间的分析:
如果在car经过pos时,1. 它已经overtaking前面的车,因为不能超车,所以它此时前面的车速度一样,经过pos的时间也一样,所以此时时间为maxArrivingTime[pos]。
2. 如果它没有超车,那么用maxArrivingTime[pos-1]再加上跑1单位距离所需要的时间即可,
因为pos是从curCar->start+1开始的,当pos = start+1时,maxArrivingTime[pos-1]必然为0;
而当pos > start +1时,pos位置可能是前面的车已经跑的地方,所以此时有两种可能,一种是前面的车已经跑完了,所以本车恢复原速度继续跑,还有一种是pos位置只有curCar跑过,不管是哪种情况,curCar经过pos-1位置时的时间都是maxArrivingTime[pos-1],而接着它是以curCar->speed速度跑,所以很轻易就能计算出它跑过pos的时间。
3. 最后取这两种时间的最大值即可。
void calculateLeavingTimeForCarInPos(RunningCar *curCar, int pos) { double timeWithNoOvertaking = maxArrivingTime[pos-1] + 1.0/curCar->getSpeed(); maxArrivingTime[pos] = max(maxArrivingTime[pos], timeWithNoOvertaking); if (isDebug) { printf("The car starts from %.0lf, ends at %.0lf, current pos at %d, time is %.2lf\n", curCar->getStart(), curCar->getEnd(), pos, maxArrivingTime[pos]); } }
运行中遇到的问题
1.在代码重构的时候犯了一个错误,我定义HighWay类,它里边有个成员变量为double *maxArrivingTime,
我在构造函数里边将它初始化为NULL。
接着在void readDataAndInitialize()函数里边我是为它分配空间并进行初始化,
当时写成了double *maxArrivingTime = new double[maxEnd+1];
for (int i = 0; i < maxEnd+1; i++)
maxArrivingTime[i] = 0;
这样就出错了,同名变量的问题,C++编译的时候不会提示错误,但运行的时候却是会出错的!
2.用示例是可以运行成功,但还是得自己也设计几个例子来测试下
比如如下运行示例:
4 1 5 4 3 6 3 4 5 2 5 8 1
我发现出问题了,所以用isDebug进行信息输出,原来是我最后输出结果的时候出了问题
//printf("%.2lf\n", maxArrivingTime[(int)curCar->getEnd()]); printf("%.2lf\n", curCar->getLeavingTime());
重构前的代码
看起来很乱,写完以后连看都不怎么想回头看int main() { vector<int> startPoints; map<int, RunningCar *> runningCars; int N; cin >> N; int maxEnd = 0; for (int i = 0; i < N; i++) { int start, end, speed; cin >> start >> end >> speed; if (maxEnd < end) maxEnd = end; RunningCar *newCar = new RunningCar(start, end, speed); runningCars[start] = newCar; startPoints.push_back(start); } double *maxArrivingTime = new double[maxEnd+1]; for (int i = 0; i < maxEnd+1; i++) maxArrivingTime[i] = 0; vector<int> sortedStarts(startPoints); sort(sortedStarts.begin(), sortedStarts.end()); int carsRunningAhead = sortedStarts.size(); while (carsRunningAhead > 0) { RunningCar *curCar = runningCars[sortedStarts[carsRunningAhead-1]]; for (int i = curCar->getStart(); i <= curCar->getEnd(); i++) { double curCarArrivingHereTime = 0; if (i >=1 && maxArrivingTime[i-1] != 0) { curCarArrivingHereTime = maxArrivingTime[i-1] + 1.0/curCar->getSpeed(); } else { curCarArrivingHereTime = ((double)i-curCar->getStart())/curCar->getSpeed(); } maxArrivingTime[i] = max(maxArrivingTime[i], curCarArrivingHereTime); } curCar->setLeavingTime(maxArrivingTime[(int)curCar->getEnd()]); carsRunningAhead--; } for (int i = 0; i < startPoints.size(); i++) { RunningCar *curCar = runningCars[startPoints[i]]; //cout << "The "<< i << "th car leaved at " << maxArrivingTime[(int)curCar->getEnd()] << endl; printf("%.2lf\n", maxArrivingTime[(int)curCar->getEnd()]); } cin >> N; return 0; }
相关文章推荐
- 常用网络命令的使用简介
- C中八进制和十六进制转义字符揭秘
- ThinkPHP--收集表单数据并实现收集添加
- ASP 页的执行造成响应缓冲区超过其配置限制
- TP-LINK路由器WR703N刷openwrt固件挂载USB摄像头(下)
- Word文件交换的电脑打开字体、排版变化的原因和解决方法!
- HashMap深度解析(二)
- 个人总结
- HashMapS深度解析(一)
- coredata数据的保存与查询
- 20条职业发展建议,送给拒绝原地踏步的你
- UGUI
- WireShark使用教程
- 观《当幸福来敲门》有感
- 第62讲:Scala中上下文界定内幕中的隐式参数与隐式参数的实战详解及其在Spark中的应用源码解析学习笔记
- 二叉树的下一个结点
- 【Unity3d开发基础】Mathf中的数学运算
- 求反素数的方法
- test9.14
- 卡諾图