hiho一下第六十五周HighWay--也属于动态规划吧

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;
}


你可能感兴趣的:(hiho一下第六十五周HighWay--也属于动态规划吧)