2013年湖南省第九届程序设计大赛 F Funny Car Racing(最短路)

1333: Funny Car Racing

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 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 (ab), 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;
}

 


你可能感兴趣的:(最短路)