poj1158 - TRAFFIC LIGHTS

133 篇文章 0 订阅

                             想看更多的解题报告:http://blog.csdn.net/wangjian8006/article/details/7870410
                                转载请注明出处:
http://blog.csdn.net/wangjian8006

 

题目大意:在一张图中,有n个点,有些点之间有通路,并且每个顶点有颜色,'B'和‘P’,当两个顶点的颜色相同,并且有通路才可以走,每个点在每个颜色有一个停留周期,周期过后会变化到下一个颜色
首先给出s与t,代表求s到t的最短时间
再然后有n个结点和m条边,首先这n行代表每个结点会有初始颜色,和再过ric[i]时间就会变化颜色,颜色为'B'的周期时间和颜色为'P'的周期时间。再接下来m条边代表无向边,边权为经过这条边的所用时间


解题思路:一个变形的最短路径,不过要注意的是推算公式,就是已经过了t时间,在v结点到u结点需要最少等待时间能够通行。只要将这个等待时间求出来,再将spfa改下就可以了

/*
spfa
Memory 540K
Time  157MS
*/
#include <iostream>
#include <queue>
using namespace std;
#define MAXV 310
#define INF 1<<27
#define min(a,b) (a>b?b:a)

int s,t,n,m,map[MAXV][MAXV];
int ric[MAXV],tb[MAXV],tp[MAXV];
char c[MAXV];

//这里状态0为B,1为P
//查看经过now_time时间后node结点的颜色,以及经过r的时间后会再次变色
int status(int now_time,int node,int &r){
	if(c[node]=='B'){
		if(now_time-ric[node]<0) {r=ric[node]-now_time;return 0;}

		now_time=(now_time-ric[node])%(tp[node]+tb[node]);
		if(now_time<tp[node]) {r=tp[node]-now_time;return 1;}
		r=tb[node]-now_time+tp[node];
		return 0;
	}else{
		if(now_time-ric[node]<0) {r=ric[node]-now_time;return 1;}

		now_time=(now_time-ric[node])%(tp[node]+tb[node]);
		if(now_time<tb[node]) {r=tb[node]-now_time;return 0;}
		r=tp[node]-now_time+tb[node];
		return 1;
	}
}

//求出已经过了ini_time时间,从start点到end点的最小等待时间
int ti(int ini_time,int start,int end){
	int c1,c2,r1,r2;
	c1=status(ini_time,start,r1);		//等待时间,第一步求两个节点经过ini_time后的状态是否一致
	c2=status(ini_time,end,r2);
	if(c1==c2) return 0;			//状态一致则不用等待
						//如果状态不一致,看两个节点经过ini_time后变到下一个状态的时间是否相同
	if(r1!=r2) return min(r1,r2);		//时间不同,则返回需要变到下一个时间短的时间即可,因为那样他们状态就相同了

	if(c1==0){                             //如果时间也相同,那么就看到下下次的状态时间
                   if(tp[start]<tb[end]) return r1+tp[start];
		if(tp[start]>tb[end]) return r2+tb[end];
		return -1;
	}else{
		if(tb[start]<tp[end]) return r1+tb[start];
		if(tb[start]>tp[end]) return r2+tp[end];
		return -1;
	}
}

void spfa(){
	queue <int>q;
	int v,i,d[MAXV],tmp;
	bool vis[MAXV];
	memset(vis,false,sizeof(vis));
	for(i=0;i<=n;i++) d[i]=INF;
	d[s]=0;
	vis[s]=true;
	q.push(s);

	while(!q.empty()){
		v=q.front();q.pop();
		vis[v]=false;

		for(i=1;i<=n;i++){
			tmp=ti(d[v],v,i);	//求此路的等待时间,为-1就永远不能经过
			if(map[v][i] && tmp!=-1 && d[i]>d[v]+map[v][i]+tmp){
				d[i]=d[v]+map[v][i]+tmp;
				if(!vis[i]){
					q.push(i);
					vis[i]=true;
				}
			}
		}
	}

	if(d[t]>=INF) printf("0\n");
	else printf("%d\n",d[t]);
}

int main(){
	int i;
	int a,b,tmp;
	while(~scanf("%d%d",&s,&t)){
		scanf("%d%d",&n,&m);
		getchar();
		for(i=1;i<=n;i++) scanf("%c %d %d %d\n",&c[i],&ric[i],&tb[i],&tp[i]);
		//记录下结点初始状态,还有多少时间变色,颜色为'B'的存在时间,颜色为'P'的存在时间
		
		for(i=1;i<=m;i++){		//输入m条无向边
			scanf("%d%d%d",&a,&b,&tmp);
			map[b][a]=map[a][b]=tmp;
		}
		
		spfa();			//求最短路径
	}
	return 0;
}


 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值