UVa Problem 10039 Railroads (铁路)

// Railroads (铁路)
// PC/UVa IDs: 111004/10039, Popularity: C, Success rate: average Level: 3
// Verdict: Accepted
// Submission Date: 2011-10-05
// UVa Run Time: 0.392s
//
// 版权所有(C)2011,邱秋。metaphysis # yeah dot net
//
// [Problem Description]
// Tomorrow morning Jill must travel from Hamburg to Darmstadt to compete in the
// regional programming contest. Since she is afraid of arriving late and being
// excluded from the contest, she is looking for the train which gets her to
// Darmstadt as early as possible. However, she dislikes getting to the station
// too early, so if there are several schedules with the same arrival time then
// she will choose the one with the latest departure time.
//
// Jill asks you to help her with her problem. You are given a set of railroad
// schedules from which you must compute the train with the earliest arrival time
// and the fastest connection from one location to another. Fortunately, Jill is
// very experienced in changing trains and can do this instantaneously, i.e., in
// zero time!
// 
// [Input]
// The very first line of the input gives the number of scenarios. Each scenario
// consists of three parts. The first part lists the names of all cities connected
// by the railroads. It starts with a number 1 < C <= 100, followed by C lines
// containing city names. All names consist only of letters.
//
// The second part describes all the trains running during a day. It starts with
// a number T <= 1,000 followed by T train descriptions. Each of them consists
// of one line with a number ti <= 100 and then ti more lines, each with a time
// and a city name, meaning that passengers can get on or off the train at that
// time at that city.
//
// The final part consists of three lines: the first containing the earliest
// possible starting time, the second the name of the city where she starts, and
// the third with the destination city. The start and destination cities are always
// different.
//
// [Output]
// For each scenario print a line containing ``Scenario i'', where i is the
// scenario number starting from 1.
//
// If a connection exists, print the two lines containing zero padded timestamps
// and locations as shown in the example. Use blanks to achieve the indentation.
// If no connection exists on the same day (i.e., arrival before midnight), print
// a line containing ``No connection''.
//
// Print a blank line after each scenario.
//
// [Sample Input]
// 2
// 3
// Hamburg
// Frankfurt
// Darmstadt
// 3
// 2
// 0949 Hamburg
// 1006 Frankfurt
// 2
// 1325 Hamburg
// 1550 Darmstadt
// 2
// 1205 Frankfurt
// 1411 Darmstadt
// 0800
// Hamburg
// Darmstadt
// 2
// Paris
// Tokyo
// 1
// 2
// 0100 Paris
// 2300 Tokyo
// 0800
// Paris
// Tokyo
//
// [Sample Output]
// Scenario 1
// Departure 0949 Hamburg
// Arrival   1411 Darmstadt
//
// Scenario 2
// No connection
//
// [解题方法]
// 题意需要求最早到达的最晚出发路线,从题目所给条件可以建模成有向图,然后从给定城市寻找到目标城市的
// 所有通路,这个可以通过宽度优先遍历来获得,与 UVa 10187 From Dusk till Dawn 类似,然后再比
// 较出发时间和到达时间,得到正确答案,当数据量较少时,可以很快得到正确结果,但是当火车列数和城市数
// 较多时,则因大量计算无法 AC,故用动态规划来加速。设立一个二维数组,表示到达时间为 T ,到达城市为
// C 时的最早出发时间,根据每个城市的路线情况来更新这个二维数组的值,最后从中间寻找是否有通路,若有
// 通路,则找出其最晚出发时间。

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <map>

using namespace std;

#define MAXV 100
#define MAXTIME 2400
#define NO_CONNECTION (-1)

struct edge
{
	int departure;
	int arrival;
	int to;

	bool operator<(const edge &e) const
	{
		return departure < e.departure;
	}
};

vector < edge > edges[MAXV];

// 缓存:到达时间为 T,到达城市为 C 的最晚出发时间。
int cache[MAXTIME][MAXV];

// DP 搜索。
void search(int tdeparture, int from, int to, string cstart, string cdestination)
{
	edge e;

	// 初始化缓存。
	for (int i = 0; i < MAXTIME; i++)
		for (int j = 0; j < MAXV; j++)
			cache[i][j] = NO_CONNECTION;

	// 排序,将出发时间早的排在前面,可以减少一些后续比较时的运行时间,可根据情况选用。
	for (int i = 0; i < MAXV; i++)
		sort(edges[i].begin(), edges[i].end());

	// 设定初始条件。
	for (int i = 0; i < edges[from].size(); i++)
	{
		e = edges[from][i];
		if (e.departure < tdeparture)
			continue;

		// 更新缓存信息。
		cache[e.arrival][e.to] = max(cache[e.arrival][e.to], e.departure);
	}

	// 动态规划。
	for (int i = 0; i < MAXTIME; i++)
		for (int j = 0; j < MAXV; j++)
		{
			// 若为 NO_CONNECTION,不需处理。
			if (cache[i][j] == NO_CONNECTION)
				continue;
			
			for (int k = edges[j].size() - 1; k >= 0; k--)
			{
				// 如果当前时间晚于此城市所有路线的最晚出发时间,则不可能在
				// 当天再乘坐火车前往其他城市。
				if (i > edges[j][k].departure)
					break;

				// 路线到达下一城市的时间。
				int arrival = edges[j][k].arrival;
				// 路线到达的下一城市。
				int next = edges[j][k].to;

				// 更新到达时间为 arrival,到达城市为 next 时的最晚出发时间。
				cache[arrival][next] =
					max(cache[arrival][next], cache[i][j]);
			}
		}

	// 查找是否存在路线。
	for (int i = 0; i < MAXTIME; i++)
		if (cache[i][to] != NO_CONNECTION)
		{
			cout << "Departure " << setw(4) << setfill('0');
			cout << cache[i][to] << " " << cstart << endl;
			cout << "Arrival   " << setw(4) << setfill('0');
			cout << i << " " << cdestination << endl;

			return;
		}

	cout << "No connection" << endl;
}

int main(int ac, char *av[])
{
	int output = 1, cases, ncities, routes, nstations;
	string city;
	int tprevious, tcurrent, tdeparture;
	string cprevious, ccurrent, cstart, cdestination;

	cin >> cases;
	while (cases--)
	{
		// 读入城市名。
		map < string, int > cities;

		cin >> ncities;
		for (int c = 0; c < ncities; c++)
		{
			cin >> city;
			cities[city] = c;
			edges[c].clear();
		}

		// 建有向图。
		cin >> routes;
		for (int c = 1; c <= routes; c++)
		{
			cin >> nstations;
			for (int m = 1; m <= nstations; m++)
			{
				cin >> tcurrent >> ccurrent;

				if (m > 1)
					edges[cities[cprevious]].push_back(
					(edge){tprevious, tcurrent, cities[ccurrent]});

				tprevious = tcurrent;
				cprevious = ccurrent;
			}
		}

		cout << "Scenario " << output++ << endl;

		// 读入出发时间,出发城市和终点城市。
		cin >> tdeparture >> cstart >> cdestination;
		// 使用动态规划找到从出发城市到终点城市最晚出发最早到达时间。
		search(tdeparture, cities[cstart], cities[cdestination],
							cstart, cdestination);
		cout << endl;
	}

	return 0;
}


  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值