Funny Car Racing(UVa-12661) :
问题描述
题目简述
There is a funny car racing in a city with n junctions and m directed roads.
The funny part is: each road is open and closed periodically. Each road is associate with two
integers (a, b), that means the road will be open for a seconds, then closed for b seconds, then open for
a seconds. . . All these start from the beginning of the race. You must enter a road when it’s open, and
leave it before it’s closed again.
Your goal is to drive from junction s and arrive at junction t as early as possible. Note that you
can wait at a junction even if all its adjacent roads are closed.
大意是:一条赛道有m个结点,通过n条路连接,每条路会周期性的开期或者关闭。并且通过每一条路都需要相应的时间。求出从起点到终点的最短所需时间。
输入/输出格式
输入格式:
There will be at most 30 test cases. The first line of each case contains four integers n, m, s, t
(1 ≤ n ≤ 300, 1 ≤ m ≤ 50, 000, 1 ≤ s, t ≤ n). Each of the next m lines contains five integers u, v, a,
b, t (1 ≤ u, v ≤ n, 1 ≤ a, b, t ≤ 105
), that means there is a road starting from junction u ending with
junction v. It’s open for a seconds, then closed for b seconds (and so on). The time needed to pass this
road, by your car, is t. No road connects the same junction, but a pair of junctions could be connected
by more than one road.
输出格式:
For each test case, print the shortest time, in seconds. It’s always possible to arrive at t from s.
样例
输入样例:
3 2 1 3
1 2 5 6 3
2 3 7 7 6
3 2 1 3
1 2 5 6 3
2 3 9 5 6
输出样例:
Case 1: 20
Case 2: 9
问题分析
解题思路
比较有意思的一道题目,加上周期性开放这个条件之后,就需要判断当车在通过某一条路径时是否需要等待的问题了。而对于这一点,实际上也比较好判断,由于道路全部是先开放后关闭,那么,以开放时间+关闭时间为一个周期,如果发现当前时间加上通过道路需要的时间对周期取模后小于开放时间,则说明在通过这条路后,这条路仍然处于开放状态,此时,直接可以通过。反之,则说明在通过这条路之后处于关闭状态,此时,需要等待一段时间才可以继续前进。等待的最短时间也非常好求。有了以上思路,跑dijkstra即可。
参考代码
#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int inf=3e8+5;
class edge
{
public:
int from,to,a,b,t;
edge(int u,int v,int aa,int bb,int tt)
{
from=u;
to=v;
a=aa;
b=bb;
t=tt;
}
};
class heapnode
{
public:
int time,index;
heapnode(int t,int id)
{
time=t;
index=id;
}
bool operator <(const heapnode& h) const
{
return time>h.time;
}
};
vector<int> graph[310];
vector<edge> edges;
priority_queue<heapnode> pq;
int d[310];
int vis[310];
int n,m,s,t;
void init()
{
for(int i=0;i<310;i++)
{
graph[i].clear();
}
while(!pq.empty()) pq.pop();
edges.clear();
memset(d,inf,sizeof(d));
memset(vis,0,sizeof(vis));
}
int dijkstra(int start,int end)
{
d[start]=0;
heapnode hn(0,start);
pq.push(hn);
while(!pq.empty())
{
heapnode x=pq.top();
pq.pop();
if(vis[x.index]==1) continue;
vis[x.index]=1;
for(int i=0;i<graph[x.index].size();i++)
{
edge& e=edges[graph[x.index][i]];
//printf("get edge(%d %d %d %d %d)\n",e.from,e.to,e.a,e.b,e.t);
int time=e.t;
int open=e.a;
int close=e.b;
if(time>open) continue;
if((d[e.from]%(open+close))+time<=open)
{
if(d[e.to]>d[e.from]+time)
{
d[e.to]=d[e.from]+time;
heapnode h(d[e.to],e.to);
pq.push(h);
}
}
else
{
int change_time=d[e.from]+time+open+close-(d[e.from]%(open+close));
if(d[e.to]>change_time)
{
d[e.to]=change_time;
heapnode h(d[e.to],e.to);
pq.push(h);
}
}
}
}
return d[t];
}
int main()
{
int count=0;
while(scanf("%d %d %d %d",&n,&m,&s,&t)==4)
{
init();
int from,to,a,b,times;
for(int i=1;i<=m;i++)
{
scanf("%d %d %d %d %d",&from,&to,&a,&b,×);
edge e(from,to,a,b,times);
edges.push_back(e);
graph[from].push_back(edges.size()-1);
}
printf("Case %d: %d\n",++count,dijkstra(s,t));
}
return 0;
}
心得体会
感觉是一道非常好的单源最短路练习题。总体来说需要思考一下,但是也不是非常困难。然后就是,以后写程序的时候变量命名还是要注意,这次重名变量就让我调了好久。。。