关于这道题的思路网上有人说用dfs+dp,这样不但编码复杂,而且容易TLE,所以我使用的是dijkstra求最短路的思路
首先在建图阶段同时建立正常的图和逆向图(端点不变,边的方向反向)。
之后首先以到达时间为权,进行dijkstra求出最早到达终点的时间。
最后在反向图上以离开时间为权进行dijkstra求出最晚出发时间。
最终运行时间为0.125s
代码如下
#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;
}