[SGU 103] Traffic Lights [最短路]

23 篇文章 0 订阅
8 篇文章 0 订阅

现在给你一个城市网络,求从某点到某点的最短路。每个点上都有一个红绿灯,仅有红绿两种颜色,按照某个周期切换,尽在边的两个端点的灯同色时,这条边才可走。

直接用最短路算法即可,走某条路径之前要加上的等待灯的时间。注意如果两个灯交替变换,那这条路时永远不能走的。

#include <cstdio>
#include <queue>

using namespace std;

int min(int a,int b) {
	return a<b?a:b;
}

struct Node {
	int fe,v,from;
	int c,r,t[2];
	void read() {
		fe=v=from=-1;
		char cc;
		scanf(" %c",&cc);
		if (cc=='B') c=0;
		else c=1;
		scanf("%d%d%d",&r,&t[0],&t[1]);
	}
};
struct Edge {
	int t,ne,v;
};
struct QueNode {
	int i,v;
	QueNode() {}
	QueNode(int ii,int vv) {
		i=ii;v=vv;
	}
	friend bool operator < (const QueNode &a,const QueNode &b) {
		return a.v>b.v;
	}
};

Node a[301];
Edge b[28000];
priority_queue<QueNode> c;
int s,t,n,m,p;

void putedge(int x,int y,int z) {
	b[p].t=y;
	b[p].v=z;
	b[p].ne=a[x].fe;
	a[x].fe=p++;
}

void cal(int &it,int &ic,int i,int t) {
	t%=(a[i].t[0]+a[i].t[1]);
	ic=a[i].c;
	if (t<a[i].r) it=a[i].r-t;
	else {
		t-=a[i].r;
		ic^=1;
		if (t<a[i].t[ic]) it=a[i].t[ic]-t;
		else {
			t-=a[i].t[ic];
			ic^=1;
			it=a[i].t[ic]-t;
		}
	}
}

int wait(int i,int j,int t) {
	int it,ic,jt,jc;
	cal(it,ic,i,t);
	cal(jt,jc,j,t);
	//printf("%d %d %d %d\n",it,ic,jt,jc);
	if (ic==jc) return 0;
	if (it!=jt) return min(it,jt);
	if (a[i].t[jc]!=a[j].t[ic]) return jt+min(a[i].t[jc],a[j].t[ic]);
	if (a[i].t[ic]!=a[j].t[jc]) return jt+a[j].t[ic]+min(a[i].t[ic],a[j].t[jc]);
	return -1;
}

void dij(int s,int t) {
	int i,j;
	a[s].v=0;
	c.push(QueNode(s,0));
	while (!c.empty()) {
		i=c.top().i;
		if (i==t) return;
		if (c.top().v==a[i].v) {
			for (j=a[i].fe;j!=-1;j=b[j].ne) {
				int tmp=wait(i,b[j].t,a[i].v);
				//printf("--%d %d %d %d\n",i,b[j].t,a[i].v,tmp);
				if (tmp!=-1) {
					tmp+=a[i].v+b[j].v;
					if (a[b[j].t].v==-1||tmp<a[b[j].t].v) {
						a[b[j].t].from=i;
						a[b[j].t].v=tmp;
						c.push(QueNode(b[j].t,tmp));
					}
				}
			}
		}
		c.pop();
	}
}

int main() {
	int i,x,y,z;
	int ans[300];
	scanf("%d%d",&s,&t);
	scanf("%d%d",&n,&m);
	for (i=1;i<=n;i++) {
		a[i].read();
	}
	p=0;
	for (i=0;i<m;i++) {
		scanf("%d%d%d",&x,&y,&z);
		putedge(x,y,z);
		putedge(y,x,z);
	}
	dij(s,t);
	if (a[t].v==-1) printf("0\n");
	else {
		printf("%d\n",a[t].v);
		p=0;
		for (i=t;i!=-1;i=a[i].from) ans[p++]=i;
		while (p) printf("%d ",ans[--p]);
		printf("\n");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值