PC/UVa:110907/10187
中文题目有问题,火车路线不是出发时间和到达时间,而是出发时间和旅行时间。
输入有几个要注意的点:
- 网上有人说火车出发时间可能会大于
24,需要注意对时间进行修正 - 判断火车时间是否满足要求时,要严格使出发时间在
18点到6点之间,并且到达时间在出发时间之后(uDebug上有一个例子中,出发时间4,旅行时间15,也就是到达时间19,单独判断时这两个时间都在合理范围内,但是并不合理)
因为从出发城市到目的城市可能存在多条路径,这道题要找血量最少的路径,找所有路径要用广搜。
广度优先搜索时要使用优先队列,否则会超时,优先队列中节点应该是按照血量排序的,然后才是途径城市最少的。
广搜的循环中,最开始写的是到达一个新的城市后,就判断是否到达目的城市。但是该点到达目标城市可能有多趟火车,在没有对火车时间排序的情况下,直接乘坐第一趟火车可能会多带一升血,所以正确的代码应该是全都加入优先队列中,直到这次取出的是目的城市。
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <queue>
#include <climits>
using namespace std;
struct Train
{
size_t dst;
size_t start, arrive;
Train(const size_t dst, const size_t start, const size_t arrive)
:dst(dst), start(start), arrive(arrive){};
};
struct Node
{
size_t city;
size_t blood;
vector<Train> path;
vector<bool> vbVisit;
};
bool operator<(const Node &n1, const Node &n2)
{
if (n1.blood > n2.blood) return true;
else if (n1.blood < n2.blood) return false;
else{
if (n1.path.size() > n2.path.size()) return true;
else if (n1.path.size() < n2.path.size()) return false;
else{
return n1.path[0].dst < n2.path[0].dst;
}
}
}
void buildGraph(vector<string> &vecCity, map<string, size_t> &mCity2ID, vector<vector<Train>> &Graph)
{
int road = 0;
cin >> road;
cin.get();
size_t ID = 0;
string strCity1, strCity2;
size_t start, duration, arrive, city1, city2;
for (int r = 0; r < road; r++)
{
cin >> strCity1 >> strCity2;
if (mCity2ID.find(strCity1) != mCity2ID.end()){
city1 = mCity2ID[strCity1];
}
else{
city1 = ID;
vecCity.push_back(strCity1);
mCity2ID[strCity1] = ID++;
Graph.push_back(vector<Train>());
}
if (mCity2ID.find(strCity2) != mCity2ID.end()){
city2 = mCity2ID[strCity2];
}
else{
city2 = ID;
vecCity.push_back(strCity2);
mCity2ID[strCity2] = ID++;
Graph.push_back(vector<Train>());
}
cin >> start >> duration;
cin.get();
arrive = start + duration;
if (start >= 24) start -= 24;
if (arrive >= 24) arrive -= 24;
//if ((start > 6 && start < 18) || (arrive > 6 && arrive < 18)) continue;
if (start >= 18 && (arrive > start || arrive <= 6) ||
start < 6 && (arrive > start && arrive <= 6)){
Graph[city1].push_back(Train(city2, start, arrive));
}
}
}
void printGraph(const vector<string> &vecCity, const map<string, size_t> &mCity2ID, const vector<vector<Train>> &Graph)
{
for (size_t city = 0; city < Graph.size(); city++)
{
const vector<Train> &vecTrain = Graph[city];
for (auto train : vecTrain)
{
//cout << vecCity[city] << " to " << vecCity[train.dst];
cout << city << " to " << train.dst;
cout << " starts at " << train.start << " and arrives at " << train.arrive << endl;
}
}
}
void findMinBlood(const vector<vector<Train>> &Graph, size_t CityStart, size_t CityArrive)
{
//cout << "from " << CityStart << " to " << CityArrive << endl;
size_t blood = UINT_MAX;
priority_queue<Node> qNode;
Node node, curr;
node.city = CityStart;
node.blood = 0;
node.vbVisit.resize(Graph.size());
node.vbVisit[CityStart] = true;
qNode.push(node);
while (!qNode.empty()){
curr = qNode.top();
qNode.pop();
if (curr.city == CityArrive){
blood = curr.blood;
break;
};
const vector<Train> vecTrain = Graph[curr.city];
for (auto train : vecTrain)
{
if (curr.vbVisit[train.dst]) continue;//路过的城市不返回
node = curr;
if (!node.path.empty()){//非出发城市,计算是否需要多带一升
size_t arrive = node.path.back().arrive;
if (arrive > 18){
if (train.start >= arrive || train.start < 6);//再出发
else node.blood++;
}
else {
if (train.start >= arrive && train.start < 6);//再出发
else node.blood++;
}
}
node.city = train.dst;
node.path.push_back(train);
node.vbVisit[train.dst] = true;
//当前点扩展后,如果到达目的地后不能直接退出
//因为当前点可能用了额外的1升血
//但是其它点扩展到目的地时可能不需要额外的1升血
qNode.push(node);
}
}
if (blood != UINT_MAX){
cout << "Vladimir needs " << blood << " litre(s) of blood." << endl;
}
else{
cout << "There is no route Vladimir can take." << endl;
}
}
int main()
{
int T = 0;
cin >> T;
cin.get();
for (int t = 0; t < T; t++)
{
vector<string> vecCity;
map<string, size_t> mCity2ID;
vector<vector<Train>> Graph;
buildGraph(vecCity, mCity2ID, Graph);
string strStartCity, strArriveCity;
cin >> strStartCity >> strArriveCity;
//printGraph(vecCity, mCity2ID, Graph);
cout << "Test Case " << t + 1 << '.' << endl;
if (strStartCity == strArriveCity){
cout << "Vladimir needs 0 litre(s) of blood." << endl;
}
else if (mCity2ID.find(strStartCity) == mCity2ID.end() ||
mCity2ID.find(strArriveCity) == mCity2ID.end()){
cout << "There is no route Vladimir can take." << endl;
}
else findMinBlood(Graph, mCity2ID[strStartCity], mCity2ID[strArriveCity]);
}
return 0;
}
/*
2
3
Ulm Muenchen 17 2
Ulm Muenchen 19 12
Ulm Muenchen 5 2
Ulm Muenchen
10
Lugoj Sibiu 12 6
Lugoj Sibiu 18 6
Lugoj Sibiu 24 5
Lugoj Medias 22 8
Lugoj Medias 18 8
Lugoj Reghin 17 4
Sibiu Reghin 19 9
Sibiu Medias 20 3
Reghin Medias 20 4
Reghin Bacau 24 6
Lugoj Bacau
*/
本文介绍了一个算法问题,目标是在夜间列车网络中找到从起点到终点所需的最小血量。通过广度优先搜索和优先队列,算法考虑了出发和到达时间的限制,以确保主角在夜间旅行中不会遇到危险。

被折叠的 条评论
为什么被折叠?



