PTA 7-12 道路管制分数 25(C++)

乌拉乌拉国有n个城市和m条道路,城市编号为1∼n。由于乌拉乌拉国每一个城市都在创城(创建文明城市),因此,城市之间的道路通行施行道路交通管制:
 已知从城市ui​到城市vi​的道路,需要时间ti​。但是一旦当道路管理员进入某条道路后,任何人在道路管理员未驶出该道路前不允许进入该道路。例如:道路管理员在第4时刻进入该道路,在路上需要花费3时,那么在第4∼6时刻不允许其他人进入改街道,只能第7时刻及其以后进入或者在第4时刻之前进入。
 现在,计算鸭知道,道路管理员从0时刻出发,依次经过g个城市,计算鸭从时刻k出发,从城市a前往城市b。请问,计算鸭最少需要多长时间。

输入格式:

输入的第一行给出两个整数n,m——表示城市的数量和道路的数量。

输入的第二行给出四个整数a,b,k,g——a,b分别表示计算鸭的初始城市和目的城市;k表示计算鸭出发时刻;g表示道路管理员需要经过的城市数量。

输入的第三行给出g个整数xi​——表示道路管理员需要经过的城市编号。

接下来m行,每行3个整数ui​,vi​,ti​——表示从ui​至vi​需要用时ti​

2≤n≤103

2≤m≤104

1≤a,b,ui​,vi​≤n

0≤k,g≤103

1≤ti​≤103

输出格式:

输出一个整数——表示计算鸭从a城市到b城市的最短用时。

输入样例:

6 5
1 6 20 4
5 3 2 4
1 2 2
2 3 8
2 4 3
3 6 10
3 5 15 

输出样例:

21

输入样例:

8 9
1 5 5 5
1 2 3 4 5
1 2 8
2 7 4
2 3 10
6 7 40
3 6 5
6 8 3
4 8 4
4 5 5
3 4 23 

输出样例:

40

代码长度限制

16 KB

时间限制

1000 ms

内存限制

64 MB

栈限制

8192 KB

注意:本题默认管理员走的点相互之间有且仅有一条边

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define int long long
#define PII pair<int,int>
#define fi first
#define pb push_back
#define sec second
#define endl '\n'
#define INF 0x3f3f3f3f
const int N=2e5+10;
const int M=1e6+10;
map<int,map<int,PII> >mp;
//来存储管理员占用一段道路的时间
int n,m,k,T,a,b,g;
int go[N],dis[N];
//go数组是管理员的路径点
vector<PII>v[N];
//邻接表 
void dij(int rt){
	memset(dis,0x3f,sizeof dis);
	dis[rt]=k;
	priority_queue<PII,vector<PII>,greater<PII> >q;
	q.push({k,rt});
	while(!q.empty()){
		int x = q.top().sec;
		q.pop();
		for(auto i : v[x]){
			int e = i.fi;
			int w = i.sec ;
			if(mp.count(x)&&mp[x].count(e)){
				if(dis[x]>=mp[x][e].fi&&dis[x]<=mp[x][e].sec){
//					cout << "now dis " << dis[e] << " " << dis[x] << endl;
					if(dis[e]>mp[x][e].sec+w){
						dis[e]=mp[x][e].sec+w;
						q.push({dis[e],e});
					}
//这里就是正常迪杰斯特拉,但是要注意如果当前时间是道路被占用时间就不要进,等到占用期过后再进入
				}else{
					if(dis[e]>dis[x]+w){
						dis[e]=dis[x]+w;
						q.push({dis[e],e});
					}
				}
			}else{
				if(dis[e]>dis[x]+w){
					dis[e]=dis[x]+w;
					q.push({dis[e],e});
				}
			} 
		}
	}
}
signed main(){
	cin >> n >> m ;
	cin >> a >> b >> k >> g ;
	for(int i=1;i<=g;i++){
		cin >> go[i];
	}
	for(int i=1;i<=m;i++){
		int a1,b1,c1;cin >> a1 >> b1 >> c1;
		v[a1].pb({b1,c1});
		v[b1].pb({a1,c1});
//建边 
	}
	int la = 0 ;
	for(int i=1;i<g;i++){
		for(auto j : v[go[i]]){
			if(j.first==go[i+1]){
				mp[go[i+1]][go[i]]=mp[go[i]][go[i+1]]={la,la+j.second};
				la+=j.second;
//两个点之间互相建边 
				break;
			}
		}
	}
//	for(int i=1;i<g;i++){
//		cout << mp[go[i]][go[i+1]].fi << " -- " << mp[go[i]][go[i+1]].sec << endl;
//	}
	dij(a);
	cout <<dis[b]-k << endl;
//注意最后输出的是消耗的时间 
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值