【SGU】103. Traffic Lights 最短路

传送门:【SGU】103. Traffic Lights


题目大意:

在一个N个点M条边的城市里,每个点上有一个交通灯,交通灯亮B、P颜色,在离开始r的时间内交通灯会亮c颜色(c为B、P中的一种),然后开始交替亮B、P颜色,B颜色亮b时间,P颜色亮p时间。M条边经过每条边都有个时间,要走一条边必须要满足这个时刻这条边的两个端点颜色相同,当你正在边上走时两端为什么颜色对你无影响。现在你要从给定的起点s走到终点t,问最小的花费以及路径。


题目分析:

首先我们要明白到达一个点的时间一定是越早越好,所以我们就可以跑最短路了。然后,我们重点要求的就是从一个点到另一个点的花费。

如果我们知道时间,那么就可以得到一个点此时的颜色以及转化过去的最小时间花费。

假设我们现在要经过边(u,v)。

设此时的时间为time_now,u现在颜色为cu_now,v现在颜色为cv_now,u变为下一颜色时的时间为cu_next_time,v变为下一颜色时的时间为cv_next_time。

显然:

1.当cu_now  = cv_now时此时u和v的颜色相同,这个时刻我们就可以走这条边。

2.当cu_now != cv_now时,如果cu_next_time != cv_next_time那么我们取其中较小的一个就好。

3.当cu_now != cv_now且cu_next_time == cv_next_time时,如果u的B颜色周期等于v的P颜色周期且u的P颜色周期等于v的B颜色周期,那么返回INF表示这条边的两个端点的颜色永远不会重叠,因此也无法经过这条边。

4.如果3不满足,说明:

(1)要么u的B颜色周期不等于v的P颜色周期。

(2)要么u的P颜色周期不等于v的B颜色周期。

如果(1)满足那么我们用cu_next_time代入一开始给的时间然后重新计算一遍就好(因为下一次的cu_next_time != cv_next_time,直接眺转至2)。

如果(2)满足那么我们将(1)重复进行两遍就好(因为第一次代入cu_next_time = cv_next_time而第二次才不同,眺转至2)。

我们用一个递归程序实现上面的操作,递归层数不超过2所以可以视为常数。

接下来是另一关键性问题:怎么求一个节点u的下一个颜色以及变为下一颜色时的最短时间?

设time_now为当前时间,color_now为此时颜色,color_next_time为变为下一颜色的最短时间。

令color_pre为节点u还未进入循环前的颜色,r为未进入循环前color_pre的持续时间,b为B颜色的持续时间,p为P颜色的持续时间。

那么当time_now小于进入循环前的持续时间时,color_now就等于初始颜色color_pre,而color_next_time就为r。

如果time_now>=r,那么令tmp = ( time_now - r ) % ( b + p )。

下面分类讨论:

1.如果color_pre为B颜色,且此时tmp<p,则当前颜色为B,时间为time_now + p - tmp。

2.如果color_pre为B颜色,且此时tmp<b,则当前颜色为P,时间为time_now + b + p - tmp。

3.如果color_pre为P颜色,且此时tmp<b,则当前颜色为P,时间为time_now + b - tmp。

4.如果color_pre为P颜色,且此时tmp<p,则当前颜色为B,时间为time_now + b + p - tmp。

既然上面的问题都解决了,那么我们就知道经过一条边的花费了,于是接下来便用最短路算法完成。记得记录路径。


代码如下:


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std ;

#pragma comment(linker, "/STACK:16777216")
#define rep( i , a , b ) for ( int i = ( a ) ; i <  ( b ) ; ++ i )
#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define clr( a , x ) memset ( a , x , sizeof a )
#define cpy( a , x ) memcpy ( a , x , sizeof a )

const int MAXN = 305 ;
const int MAXE = 100005 ;
const int INF = 0x3f3f3f3f ;

struct Traffic {
	int color_pre , r , b , p ;
	void input () {
		char color[2] ;
		scanf ( "%s%d%d%d" , color , &r , &b , &p ) ;
		color_pre = color[0] == 'B' ? 0 : 1 ;
	}
} ;

struct Edge {
	int v , c , n ;
	Edge () {}
	Edge ( int v , int c , int n ) : v ( v ) , c ( c ) , n ( n ) {}
} ;

Traffic node[MAXN] ;
Edge E[MAXE] ;
int H[MAXN] , cntE ;
int d[MAXN] ;
int vis[MAXN] ;
int pre[MAXN] ;
int Q[MAXN] , head , tail ;
int S[MAXN] , top ;
int s , t ;
int n , m ;

void clear () {
	cntE = 0 ;
	clr ( H , -1 ) ;
}

void addedge ( int u , int v , int c ) {
	E[cntE] = Edge ( v , c , H[u] ) ;
	H[u] = cntE ++ ;
}

void get_color ( int u , int time_now , int& color_now , int& color_next_time ) {
	if ( time_now < node[u].r ) {//in pre
		color_now = node[u].color_pre ;
		color_next_time = node[u].r ;
	} else {//in loop
		int tmp = ( time_now - node[u].r ) % ( node[u].b + node[u].p ) ;
		if ( node[u].color_pre == 0 ) {
			if ( tmp < node[u].p ) {
				color_now = 1 ;
				color_next_time = time_now + node[u].p - tmp ;
			} else {
				color_now = 0 ;
				color_next_time = time_now + node[u].b + node[u].p - tmp ;
			}
		} else {
			if ( tmp < node[u].b ) {
				color_now = 0 ;
				color_next_time = time_now + node[u].b - tmp ;
			} else {
				color_now = 1 ;
				color_next_time = time_now + node[u].b + node[u].p - tmp ;
			}
		}
	}
}

int get_cost ( int u , int v , int time_now ) {
	int cu_now , cv_now , cu_next_time , cv_next_time ;
	get_color ( u , time_now , cu_now , cu_next_time ) ;
	get_color ( v , time_now , cv_now , cv_next_time ) ;
	if ( cu_now == cv_now ) return time_now ;//1
	if ( cu_next_time == cv_next_time ) {
		if ( node[u].b == node[v].p && node[u].p == node[v].b ) return INF ;//3
		return get_cost ( u , v , cu_next_time ) ;//4
	}
	return min ( cu_next_time , cv_next_time ) ;//2
}

void spfa () {
	clr ( d , INF ) ;
	clr ( vis , 0 ) ;
	head = tail = 0 ;
	Q[tail ++] = s ;
	pre[s] = 0 ;
	d[s] = 0 ;
	while ( head != tail ) {
		int u = Q[head ++] ;
		if ( head == MAXN ) head = 0 ;
		vis[u] = 0 ;
		for ( int i = H[u] ; ~i ; i = E[i].n ) {
			int v = E[i].v ;
			int cost = E[i].c + get_cost ( u , v , d[u] ) ;
			if ( d[v] > cost ) {
				d[v] = cost ;
				pre[v] = u ;
				if ( !vis[v] ) {
					vis[v] = 1 ;
					Q[tail ++] = v ;
					if ( tail == MAXN ) tail = 0 ;
				}
			}
		}
	}
	if ( d[t] == INF ) printf ( "0\n" ) ;//not exist a path
	else {
		printf ( "%d\n" , d[t] ) ;
		top = 0 ;
		int x = t ;
		while ( x ) {
			S[top ++] = x ;
			x = pre[x] ;
		}
		rev ( i , top - 1 , 0 ) printf ( "%d%c" , S[i] , i ? ' ' : '\n' ) ;
	}
}

void solve () {
	clear () ;
	int u , v , c ;
	scanf ( "%d%d" , &n , &m ) ;
	For ( i , 1 , n ) node[i].input () ;
	rep ( i , 0 , m ) {
		scanf ( "%d%d%d" , &u , &v , &c ) ;
		addedge ( u , v , c ) ;
		addedge ( v , u , c ) ;
	}
	spfa () ;
}

int main () {
	while ( ~scanf ( "%d%d" , &s , &t ) ) solve () ;
	return 0 ;
}


你可能感兴趣的:(sgu)