题目原文已经找不到了,大体的内容如下:
以地面为y=0建立坐标,有人从(0,H)向下落,途中有些平台,人落到平台上会立刻失去所有速度。人可以从平台两端以水平初速度V往下跳,下跳过程服从平抛运动,V最小为0.001,最大不超过Vmax。给定H,Vmax以及所有平台左端点坐标和长度,求人下落到地面y=0的最短时间。
思路
对每个平台,维护一个最短到达时间的变量。
从最高的平台开始,对每个平台Platform[i],找出从该平台出发能到达的平台Platform[j],更新Platform[j]的最短到达时间为原有最短到达时间Tj与Platform[i]的到达时间Ti+Sqrt(2(Hi-Hj)/g)的较小者。
对每个平台计算能到达平台时,用“允许速度区间”的方法处理高处平台对底处平台的遮挡。
代码实现
#include <iostream>
#include <list>
#include <iomanip>
#include <vector>
#include <fstream>
#include <algorithm>
#include <iterator>
#include <cmath>
#include <ctime>
typedef std::pair<double, double> Interval;
class Platform
{
public:
double leftBoundary;
double rightBoundary;
double height;
double velocity;
double timeUsed;
int prevPlatform;
int code;
char direction;
Platform(int code, double x, double y, double w)
{
this->code = code;
leftBoundary = x;
rightBoundary = x + w;
height = y;
timeUsed = 1e30;
}
bool operator < (const Platform& other)
{
return height > other.height || height == other.height && code < other.code;
}
bool operator >= (const Platform& other)
{
return !(*this < other);
}
};
class Game
{
const double g = 9.8;
double maxVelocity;
double height;
std::vector<Platform> platforms;
public:
Game(std::ifstream& fin)
{
fin >> height;
fin >> maxVelocity;
fin.get();
std::list<Platform> tempPlatforms;
int i = 0;
double x, y, w;
while (!fin.eof() && fin.peek() != '\n' && fin.peek() != ';')
{
fin >> x >> y >> w;
fin.get();
tempPlatforms.push_back(Platform(i, x, y, w));
i++;
}
while (!fin.eof() && fin.get() != ';');
tempPlatforms.push_back(Platform(-1, -1e100, 0, 2e100));
std::copy(tempPlatforms.begin(), tempPlatforms.end(), std::back_inserter(platforms));
platforms[0].timeUsed = 0;
std::sort(platforms.begin(), platforms.end());
}
private:
void calculateTime()
{
unsigned int i = 0;
while (i < platforms.size() && platforms[i].code != 0)
i++;
while (i < platforms.size())
{
std::list<Interval> leftIntervals;
std::list<Interval> rightIntervals;
leftIntervals.push_back(Interval(0.001, maxVelocity));
rightIntervals.push_back(Interval(0.001, maxVelocity));
for (unsigned int j = i + 1; j < platforms.size() && !(leftIntervals.empty() && rightIntervals.empty()); j++)
{
double deltaHeight = platforms[i].height - platforms[j].height;
if (fabs(deltaHeight) < 1e-10)
continue;
double deltaTime = sqrt(2 * deltaHeight / g);
if (!leftIntervals.empty() && platforms[j].leftBoundary < platforms[i].leftBoundary)
{
double maxReachableVelocity = (platforms[i].leftBoundary - platforms[j].leftBoundary) / deltaTime;
double minReachableVelocity = (platforms[i].leftBoundary - platforms[j].rightBoundary) / deltaTime;
std::list<Interval>::iterator min = leftIntervals.begin(), max = leftIntervals.begin();
bool accessiable = false;
double speed = 0;
while (min!=leftIntervals.end() && (*min).second < minReachableVelocity) ++min;
while (max!=leftIntervals.end() && (*max).second < maxReachableVelocity) ++max;
if (min != leftIntervals.end())
{
if (min == max)
{
if (maxReachableVelocity >(*min).first) {
accessiable = true;
if (minReachableVelocity < (*min).first)
{
speed = ((*min).first + maxReachableVelocity) / 2;
(*min).first = maxReachableVelocity;
}
else
{
speed = (minReachableVelocity + maxReachableVelocity) / 2;
double temp = (*min).first;
(*min).first = maxReachableVelocity;
leftIntervals.insert(min, Interval(temp, minReachableVelocity));
}
}
}
else
{
accessiable = true;
if (max != leftIntervals.end() && maxReachableVelocity > (*max).first)
(*max).first = maxReachableVelocity;
if (minReachableVelocity <= (*min).first)
{
speed = ((*min).first + (*min).second) / 2;
leftIntervals.erase(min, max);
}
else
{
speed = (minReachableVelocity + (*min).second) / 2;
(*min).second = minReachableVelocity;
++min;
if (min != max)
leftIntervals.erase(min, max);
}
}
}
if (accessiable && platforms[j].timeUsed > platforms[i].timeUsed + deltaTime)
{
platforms[j].timeUsed = platforms[i].timeUsed + deltaTime;
platforms[j].prevPlatform = i;
platforms[j].direction = 'L';
platforms[j].velocity = speed;
}
}
if (!rightIntervals.empty() && platforms[j].rightBoundary > platforms[i].rightBoundary)
{
double maxReachableVelocity = (platforms[j].rightBoundary - platforms[i].rightBoundary) / deltaTime;
double minReachableVelocity = (platforms[j].leftBoundary - platforms[i].rightBoundary) / deltaTime;
std::list<Interval>::iterator min = rightIntervals.begin(), max = rightIntervals.begin();
bool accessiable = false;
double speed = 0;
while (min != rightIntervals.end() && (*min).second < minReachableVelocity) ++min;
while (max != rightIntervals.end() && (*max).second < maxReachableVelocity) ++max;
if (min != rightIntervals.end())
{
if (min == max && min != rightIntervals.end())
{
if (maxReachableVelocity >(*min).first) {
accessiable = true;
if (minReachableVelocity < (*min).first)
{
speed = ((*min).first + maxReachableVelocity) / 2;
(*min).first = maxReachableVelocity;
}
else
{
speed = (minReachableVelocity + maxReachableVelocity) / 2;
double temp = (*min).first;
(*min).first = maxReachableVelocity;
rightIntervals.insert(min, Interval(temp, minReachableVelocity));
}
}
}
else
{
accessiable = true;
if (max != rightIntervals.end() && maxReachableVelocity > (*max).first)
(*max).first = maxReachableVelocity;
if (minReachableVelocity <= (*min).first)
{
speed = ((*min).first + (*min).second) / 2;
rightIntervals.erase(min, max);
}
else
{
speed = (minReachableVelocity + (*min).second) / 2;
(*min).second = minReachableVelocity;
++min;
rightIntervals.erase(min, max);
}
}
}
if (accessiable && platforms[j].timeUsed > platforms[i].timeUsed + deltaTime)
{
platforms[j].timeUsed = platforms[i].timeUsed + deltaTime;
platforms[j].prevPlatform = i;
platforms[j].direction = 'R';
platforms[j].velocity = speed;
}
}
}
i++;
}
}
public:
void output(std::ofstream& fout)
{
calculateTime();
int i = platforms.size() - 1;
std::cout << platforms[i].timeUsed << std::endl;
std::list<char> dir;
std::list<int> to;
std::list<double> v;
while (platforms[i].code != 0)
{
dir.push_front(platforms[i].direction);
to.push_front(platforms[i].code);
v.push_front(platforms[i].velocity);
i = platforms[i].prevPlatform;
}
std::list<char>::iterator ItrC = dir.begin();
std::list<int>::iterator ItrI = to.begin();
std::list<double>::iterator ItrD = v.begin();
while (ItrC != dir.end())
{
fout << *ItrC++ << ' ' << *ItrI++ << ' ' << std::fixed << std::setprecision(3) << *ItrD++ << std::endl;
}
}
};
int main()
{
time_t start = clock();
std::ifstream inputFile;
inputFile.open("input22.txt", std::ios::in);
std::ofstream outputFile;
outputFile.open("output.txt", std::ios::out);
if (inputFile.fail() || outputFile.fail())
{
std::cerr << "Cannot open the required file!" << std::endl;
}
while (true)
{
Game game(inputFile);
game.output(outputFile);
if (inputFile.eof())
break;
else
outputFile << ';' << std::endl;
}
std::cout << clock() - start << std::endl;
return 0;
}