1333: Funny Car Racing
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 78 Solved: 19
[ Submit][ Status][ Web Board]
Description
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.
Input
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.
Output
For each test case, print the shortest time, in seconds. It's always possible to arrive at t from s.
Sample Input
3 2 1 31 2 5 6 32 3 7 7 63 2 1 31 2 5 6 32 3 9 5 6
Sample Output
Case 1: 20
Case 2: 9
题意:
给你N个点,M条边,每条边有开启时间l,关闭时间R和通过改变所需的时间t,该路开启时间持续 I 后 关闭,然后关闭时间持续R后开启,一直循环
然后给你一个起点S, 一个终点V, 求S到V所需的最短时间
方法:
用最短路即可求解,不过再在更新点i到起点的最短距离时做一下处理
PS: 做训练赛的时候我就想到这题用最短路应该就能做的,不过这题 是英文题,SO 我看错题目了。。。。
首先我就看到两点之间可能有多条边,然后因为题目描述中图的边是路, 所以我以为边是双向的, 其实是单向边
代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <limits.h>
using namespace std;
#define maxn 300
#define maxm 50000
struct node
{
int x, y, l, r, s;
}edge[2*maxm+5];
int sum[maxn+5];
int vis[maxn+5];
int dis[maxn+5];
int n, m, be, end;
int cmp(node x, node y)
{
return x.x< y.x;
}
void dij()
{
for(int c= 1; c<= n; c++)
{
int min= INT_MAX;
int pos= -1;
for(int i= 1; i<= n; i++)
if(dis[i]< min && !vis[i])
{
min= dis[i];
pos= i;
}
if(min== INT_MAX)
break;
vis[pos]= 1; //加入集合中
for(int i= sum[pos-1]+1; i<= sum[pos]; i++)
{
if(!vis[edge[i].y] && edge[i].l>= edge[i].s)
{
int lt= edge[i].l - dis[pos]%(edge[i].l + edge[i].r); //路开启所剩的时间
int cost; //通过这条路需要的时间
if(lt>= edge[i].s) //剩余时间足够通过这条路
cost= edge[i].s;
else
cost= lt + edge[i].r + edge[i].s;// 时间不够等待下次路开启
if(dis[pos]+ cost < dis[edge[i].y])
dis[edge[i].y]= dis[pos] + cost; //更新最短路
}
}
}
}
int main()
{
int T= 0;
while(scanf("%d %d %d %d",&n,&m,&be,&end)!=EOF)
{
int u, v, a, b, t;
memset(sum, 0, sizeof(sum));
for(int i= 1; i<= m; i++)
{
scanf("%d %d %d %d %d",&u, &v, &a, &b, &t);
edge[i]= (node){u, v, a, b, t};
// edge[i+m]= (node){v, u, a, b, t};
sum[u]++; //是单向边不是双向边
// sum[v]++;
}
// sort(edge+1, edge+2*m+1, cmp);
sort(edge+1, edge+m+1, cmp);
for(int i= 2; i<= n; i++)
sum[i]= sum[i] + sum[i-1];
for(int i= 1; i<= n; i++)
dis[i]= 123456789;
for(int i= sum[be-1]+1; i<= sum[be]; i++)
{
if(edge[i].l>= edge[i].s && dis[edge[i].y]> edge[i].s) //时间够通过这条道路
dis[edge[i].y]= edge[i].s;
}
memset(vis, 0, sizeof(vis));
vis[be]= 1; //标记起点已经走过
dij();
T++;
printf("Case %d: %d\n",T,dis[end]);
}
return 0;
}