10039 Railroads

原题:10039 Railroads

题目大意:

Jill要乘火车去参加比赛。为了避免迟到,她要选择能最早到达的方案。

Jill换乘时间非常快,看做0.

输入:第一行场景数,每个场景由3部分组成

           part1: 列举所有被铁路连接的城市的名称

                     第一行是城市数 1<C<100,接下来的C行是城市的名称

            part2:描述当天所有会运行的火车。 

                      第一行T表示有T班火车。T<1000

                      每班火车都由一个数字ti,其后跟随ti行描述。

                       ti表示会经过多少站。

                       ti后的每一行 站名和时间   在该时间该站可以上下车

            part3:第三部分由三行表示。

                       第一行最早出发时间,第二行出发地,第三行目的地


要求输出出发地出发时间,目的地和到达时间

如果存在多种方式使到达时间最小,选出发时间最晚的那一个。


思考:

每个点包含时间、站名,除了以及存在的联通关系,该图是一个有向图

<u,v>存在的条件是   u,v站名相同&&u.time<=v.time


题目要求如果存在多种方式使到达时间最小,选出发时间最晚的那一个。

第一个前提是到达时间最早,第二个前提是出发时间最晚

因此比较适合逆着去寻路


把站名是目的地的点  按照   时间 从早到晚排序(从小到大)  ---->如果不存在这样的点,显然不存在所需的路

从小到大依次处理:

dfs

寻找一条从目的地到出发地的路,如果有多条,选出发时间最大的那个。如果找到,结束循环。输出

否则换下一个出发点,重复上述过程


如果一直没有找到,则不存在这样的路。


因此我们需要建立一个逆序图


其实通过优化,实际上还有另一种思路:

其实这题可以看成最短路径问题

先从最早出发时间开始,使用dijkstra算法找到最早到达时间。(把到达时间看做权)

再从最早到达时间开始,逆序寻找最晚出发时间。(以出发时间为权)

参考博客:10039

#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <cstdio>

#define MAX_CITY 200

using namespace std;

//边结构体
struct Edge
{
	int y;
	int d,a;
	struct Edge *next;
	
	Edge(int dst,int dep,int arr):y(dst),d(dep),a(arr),next(NULL) {;}
	Edge () {;}
};

int nCity;
Edge* edges[MAX_CITY]; //正向图
Edge* reverse[MAX_CITY]; //逆向图

map <string,int> m;	//城市与编号的映射

//分别向正向图与逆向图中加入边
void insert_edge (int nsc)
{
	int nstation,time,last,lastTime;
	int current,currentTime;
	string city;
	for (int i=0;i<nsc;i++)
	{
		cin >> nstation;
		cin>>time>>city;
		last = m[city];
		lastTime = time;
		for (int j=1;j<nstation;j++)
		{
			cin >> time >> city;
			current = m[city];
			Edge *newEdge = new Edge(current,lastTime,time);
			newEdge->next = edges[last];
			edges[last] = newEdge;
			Edge *revEdge = new Edge (last,lastTime,time);
			revEdge->next = reverse[current];
			reverse[current] = revEdge;

			last = current;
			lastTime = time;
		}
	}
}

//通过最早出发时间计算最早到达时间
//使用dijkstra算法
int calDst (int src,int dst,int sTime)
{
	//arrival表示到达某点的最早时间
	int arrival[MAX_CITY],v,min;
	bool intree[MAX_CITY];

	for (int i=0;i<nCity;i++)
		arrival[i] = INT_MAX;
	memset (intree,false,sizeof(intree));
	arrival[src] = sTime;
	intree[src]= true;
	v = src;

	do
	{
		for (Edge* p=edges[v];p;p=p->next)
		{
			//只有出发时间 >= 到达v的时间才是有效的边
			if (p->d>=arrival[v])
			{
				int y =  p->y;
				//当到达y的时间较小时更新arrival
				if (p->a < arrival[y])
					arrival[y] = p->a;
			}
		}
		min = INT_MAX;	
		v = -1;
		for (int i=0;i<nCity;i++)
			if (!intree[i] && arrival[i]<min)
			{
				v = i;
				min = arrival[i];
			}
		intree[v] = true;
	}while (v!=-1);

	return arrival[dst];
}

//利用上面算出的最早到达时间计算最晚出发时间
//注意这个函数用的是反向图
int calSrc (int dst,int src,int eTime)
{
	//depture 表示从某点出发的最晚时间
	int depture[MAX_CITY],v,max;
	bool intree[MAX_CITY];

	for (int i=0;i<nCity;i++)
		depture[i] = -1;
	memset (intree,false,sizeof(intree));
	depture[dst] = eTime;
	intree[dst]= true;
	v = dst;

	do
	{
		for (Edge* p=reverse[v];p;p=p->next)
		{
			if (p->a<=depture[v])
			{
				//和上面的函数相似
				int y =  p->y;
				if (p->d > depture[y])
					depture[y] = p->d;
			}
		}
		max=0;	
		v = -1;
		for (int i=0;i<nCity;i++)
			if (!intree[i] && depture[i]>max)
			{
				v = i;
				max = depture[i];
			}
		intree[v] = true;
	}while (v!=-1);

	return depture[src];
}

int main (void)
{
	int testCase,nsc,src,dst,sTime,eTime,realSTime;
	string str,srcStr,dstStr;
	cin >> testCase;
	for (int test = 1;test<=testCase;test++)
	{
		cin >> nCity;	
		m.clear();
		memset (edges,NULL,sizeof(edges));
		memset (reverse,NULL,sizeof(reverse));

		for (int i=0;i<nCity;i++)
		{
			cin >> str;
			m[str] = i;
		}
		cin >> nsc;
		insert_edge (nsc);
		cin >> sTime;
		cin >> srcStr >> dstStr;
		src = m[srcStr];
		dst = m[dstStr];

		eTime = calDst (src,dst,sTime);
		cout <<"Scenario "<<test <<endl;
		if (eTime<INT_MAX)
		{
			realSTime = calSrc (dst,src,eTime);
			printf ("Departure %04d %s\n",realSTime,srcStr.c_str());
			printf ("Arrival   %04d %s\n",eTime,dstStr.c_str());
		}
		else
			printf ("No connection\n");
		cout << endl;
	}
	return 0;
}



自己的代码如下:


#include<iostream>
#include<stdio.h>
#include<vector>
#include<map>
#include<string>
#include<string.h>

using namespace std;

struct Edge {
	int d, a, c;
	Edge* next;

	Edge(int dst, int depart, int arrive) {
		c = dst;
		d = depart;
		a = arrive;
		next = NULL;
	}

	Edge() { next = NULL; }
};

Edge* edges[110];
Edge* reverseEdges[110];
map<string, int> m;
const int INF = 1 << 20;


//建立正向图和逆向图
void create(int nTrain)
{
	while (nTrain--)
	{
		int nstation, time, lastTime, currTime, lastCity, currCity;
		string city;

		cin >> nstation;
		cin >> time >> city;

		lastTime = time;
		lastCity = m[city];

		nstation--;
		while (nstation--)
		{
			cin >> time >> city;
			currTime = time;
			currCity = m[city];
			//正向图
			Edge* e1 = new Edge(currCity, lastTime, currTime);
			e1->next = edges[lastCity];
			edges[lastCity] = e1;
			//逆向图
			Edge*e2 = new Edge(lastCity, lastTime, currTime);
			e2->next = reverseEdges[currCity];
			reverseEdges[currCity] = e2;

			lastTime = currTime;
			lastCity = currCity;
		}
	}
}

//如果找到了最小到达时间,返回到达时间,否则返回的是INF
int minArriveTime(int startTime, int src, int des, int ncity)
{
	//arrive用来维护最早到达时间
	int arrive[110], have[110];

	//初始化arrive和have
	for (int i = 0; i <= ncity; i++)
		arrive[i] = INF;
	memset(have, 0, sizeof(have));

	//初始化到每一个点的最小到达时间
	have[src] = 1;
	arrive[src] = startTime;
	for (Edge*p = edges[src]; p; p = p->next)
	{
		int city = p->c;
		//只有到达的时间早于出发的时间才能更新
		if(arrive[src]<=p->d)
		   arrive[city] = p->a;
	}

	int n = ncity - 1;
	while (n--)
	{
		int min, next;
		//找到arrive最小的那个
		min = INF-1; next = 0;
		for (int i = 1; i <= ncity; i++)
		{
			if (!have[i] && arrive[i] <= min)
			{
				min = arrive[i];
				next = i;
			}
		}

			//更新src到每一个城市的最小到达时间
		for (Edge*p = edges[next]; p; p=p->next)
		{
			int city = p->c;
				//只有到达时间早于出发时间
			if (arrive[next] <= p->d)
			{
				if (arrive[city] > p->a)arrive[city] = p->a;
			}

		}

	}
	return arrive[des];
}

//逆向搜索,找到最大离开时间 Dijkstra
int maxLeaveTime(int arriveTime,int src, int des, int ncity)
{
	//depart表示离开某点的最晚时间
	int depart[110],have[110];

	for (int i = 1; i <= ncity; i++)
		depart[i] = -1;
	memset(have, 0, sizeof(have));

	have[des] = 1;
	depart[des] = arriveTime;

	for (Edge*p = reverseEdges[des]; p; p = p->next)
	{
		//最晚出发时间应该大于到达时间
		if(depart[des]>=p->a)
		   depart[p->c] = p->d;
	}

	int num = ncity-1;
	while (num--)
	{
		int max = 0, next = 0;
		for (int i = 1; i <= ncity; i++)
		{
			if (!have[i] && depart[i] >= max)
			{
				max = depart[i];
				next = i;
			}
		}

		have[next] = 1;
		for (Edge*p = reverseEdges[next]; p; p = p->next)
		{
			if (depart[next] >= p->a)
			{
				if (depart[p->c] < p->d)depart[p->c] = p->d;
			}
		}

	}
	return depart[src];

}

int main()
{

	freopen( "c:\\data\\10039.txt", "r", stdin);
	int scenarios, ncity, nTrain, startTime;
	string source, destination;

	cin >> scenarios;
	for(int cas=1;cas<=scenarios;cas++)
	{
		cin >> ncity;
		//为每个城市创建映射
		for (int i = 1; i <= ncity; i++)
		{
			string cityname;
			cin >> cityname;
			m[cityname] = i;
		}

		//创建正向和逆向图
		memset(edges, 0, sizeof(edges));
		memset(reverseEdges, 0, sizeof(edges));
		cin >> nTrain;
		create(nTrain);

		//从最早出发时间寻找最早到达时间,以到达时间为权
		cin >> startTime >> source >> destination;
		int minATime = minArriveTime(startTime, m[source], m[destination], ncity);
		cout << "Scenario " << cas << endl;
		if (minATime == INF)
			cout << "No connection" << endl;
		else
		{
		   int maxLTime = maxLeaveTime(minATime, m[source], m[destination], ncity);
			printf("Departure %04d %s\n", maxLTime, source.c_str());
			printf("Arrival   %04d %s\n", minATime, destination.c_str());
		}
		cout<<endl;

	}
	return 0;
}





















 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值