POJ 3594 带限制的最短路 枚举+SPFA

题意:给出一个有向图,通过每条边花费的时间wi以及每条边的通行时间[bi,ei],问起点到终点路上花费时间(到达时间-出发时间,时间默认最开始是0)最短是多少。
其实就是一个加了限制条件的最短路,SPFA可以做到,其实SPFA是可以加很多扩展内容。
但是注意,由于有通行时间的存在,中途有可能需要等待,而答案要求是到达时间减去出发时间,所以这个等待要尽量放在开始之前,就是尽量晚出发。然而我们并不知道到底是哪个时间出发比较好,所以我们枚举这个出发时间,再用SPFA求最短路。
d[i]表示到i的最短时间(加上出发前的等待时间,就是说d[s] = k,k是所枚举的出发时间,这样d[i]值也就代表着走到i点时的时间),SPFA中需要扩展的内容仅仅是在松弛条件中加上关于通行时间的特判:如果需要等待,那么就要加上等待的时间。再说清楚点,原本是d[v] > d[u]+w的判断变成了d[v] > max(d[u], b) + w && d[u]+w <= e,后一半是要保证在结束通行前可以通过这条边,前一半里的max就是,如果需要等待,那么从u出发时间就是b而不是d[u],到达点v的时间d[v]就变成了从u出发的时间b加上通过这条边本身需要的时间w。
#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;

int n, m, s, t, ans = 1<<30, d[101], Mn = 1<<30, Mx;
bool inq[101];
vector <int> G[101];
queue <int> q;

struct edge{
	int u, v, w, b, e;
}E[1001];

void read(){
	scanf("%d %d %d %d", &n, &m, &s, &t);
	for(int i = 1; i <= m; i++){
		scanf("%d %d %d %d %d", &E[i].u, &E[i].v, &E[i].b, &E[i].e, &E[i].w);
		if(E[i].e - E[i].b + 1 < E[i].w) continue;
		G[E[i].u].push_back(i);
		Mn = min(Mn, E[i].b);
		Mx = max(Mx, E[i].e);
	}
}

void spfa(int k){
	memset(d, 0x7f, sizeof d);
	d[s] = k;
	q.push(s);
	while(!q.empty()){
		int u = q.front(); q.pop();
		inq[u] = 0;
		for(int i = 0; i < G[u].size(); i++){
			int t = G[u][i], v = E[t].v, b = E[t].b, e = E[t].e, w = E[t].w;
			if(d[v] > max(d[u], b) + w && d[u]+w <= e){
				d[v] = d[u] + w;
				if(b > d[u]) d[v] += b-d[u];
				if(!inq[v]) q.push(v), inq[v] = 1; 
			}
		}
	} 
}

int main()
{
	read();
	for(int i = Mn; i <= Mx; i++){
		spfa(i);
		ans = min(ans, d[t]-i);
	}
	if(ans <= 1e6) printf("%d", ans);
	else printf("Impossible");
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值