您的位置:首页 > 其它

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来记录车的状态
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: