[分层图最短路]限高杆 2020年蓝桥杯

48 篇文章 0 订阅

某市有 n 个路口,有 m 段道路连接这些路口,组成了该市的公路系统。

其中一段道路两端一定连接两个不同的路口。

道路中间不会穿过路口。

由于各种原因,在一部分道路的中间设置了一些限高杆,有限高杆的路段货车无法通过。

在该市有两个重要的市场 A 和 B,分别在路口 1 和 n 附近,货车从市场 A 出发,首先走到路口 1,然后经过公路系统走到路口 n,才能到达市场 B。

两个市场非常繁华,每天有很多货车往返于两个市场之间。

市长发现,由于限高杆很多,导致货车可能需要绕行才能往返于市场之间,这使得货车在公路系统中的行驶路程变长,增加了对公路系统的损耗,增加了能源的消耗,同时还增加了环境污染。

市长决定要将两段道路中的限高杆拆除,使得市场 A 和市场 B 之间的路程变短。

请问最多能减少多长的距离?

输入格式

输入的第一行包含两个整数 n,m,分别表示路口的数量和道路的段数。

接下来 m 行,每行四个整数 a,b,c,d,表示路口 a 和路口 b 之间有一段长度为 c 的道路。如果 d 为 0,表示这段道路上没有限高杆;如果 d 为 1,表示这段道路上有限高杆。

两个路口之间可能有多段道路。

输入数据保证在不拆除限高杆的情况下,货车能通过公路系统从路口 1 正常行驶到路口 n。

输出格式

输出一行,包含一个整数,表示拆除两段道路的限高杆后,市场 A 和市场 B 之间的路程最大减少多长距离。

数据范围

对于 30% 的评测样例,2≤n≤10,1≤m≤20,1≤c≤100。
对于 50% 的评测样例,2≤n≤100,1≤m≤1000,1≤c≤1000。
对于 70% 的评测样例,2≤n≤1000,1≤m≤10000,1≤c≤10000。
对于所有评测样例,2≤n≤10000,2≤m≤100000,1≤c≤10000,至少有两段道路有限高杆。

输入样例:

5 7
1 2 1 0
2 3 2 1
1 3 9 0
5 3 8 0
4 3 5 1
4 3 9 0
4 5 4 0

输出样例:

6

样例解释

只有两段道路有限高杆,全部拆除后,1 到 n 的路程由原来的 17 变为了 11,减少了 6。

题意: n个点m条边,其中有若干条边在原图中并不存在,现在要从中重建2条边,使得从点1到点n的最短距离减小值最大。

分析: 由于涉及到从中选k条边,可以看出是个分层图的题目,对于这道题目中k等于2,所以算上原图需要建一个三层的图。每层首先都需要初始化成原图,之后层与层之间再通过附加边来连接,比如现在有一条从点1到点2的可选的边,那么第1层的点1到第2层的点2就需要加上这条边,由于是双向边,所以第1层的点2到第2层的点1也需要加上这条边,要注意边的方向一定是从上一层的点到下一层的点,防止跑着跑着跑回了上一层,类似这样把所有附加边都加完后跑一个dijkstra最短路就行了,第i层的dis[n]就表示经过了i-1条附加边到达终点的最短路,由于并不清楚最终具体经过了几条附加边,所以需要这三层的dis[n]取最小值。

具体代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#define pii pair<int, int>
#define inf 0x3f3f3f3f
using namespace std;

vector<pii> p[30005], q[10005];//q为原图,p为分层图 
bool vis_p[30005], vis_q[10005];
int d_p[30005], d_q[10005];

void dij1(){
	priority_queue<pii, vector<pii>, greater<pii>> qu;
	d_p[1] = 0;
	qu.push(make_pair(d_p[1], 1));
	while(qu.size()){
		int now = qu.top().second;
		qu.pop();
		if(vis_p[now]) continue;
		vis_p[now] = true;
		for(int i = 0; i < p[now].size(); i++){
			int to = p[now][i].second, w = p[now][i].first;
			if(d_p[to] > d_p[now]+w){
				d_p[to] = d_p[now]+w;
				qu.push(make_pair(d_p[to], to));
			}
		}
	}
}

void dij2(){
	priority_queue<pii, vector<pii>, greater<pii>> qu;
	d_q[1] = 0;
	qu.push(make_pair(d_q[1], 1));
	while(qu.size()){
		int now = qu.top().second;
		qu.pop();
		if(vis_q[now]) continue;
		vis_q[now] = true;
		for(int i = 0; i < q[now].size(); i++){
			int to = q[now][i].second, w = q[now][i].first;
			if(d_q[to] > d_q[now]+w){
				d_q[to] = d_q[now]+w;
				qu.push(make_pair(d_q[to], to));
			}
		}
	}
}

signed main()
{
	int n, m;
	cin >> n >> m;
	memset(d_p, 0x3f, sizeof d_p);
	memset(d_q, 0x3f, sizeof d_q);
	for(int i = 1; i <= m; i++){
		int u, v, w, c;
		scanf("%d%d%d%d", &u, &v, &w, &c);
		if(!c){
			//构建原图 
			q[u].push_back(make_pair(w, v));
			q[v].push_back(make_pair(w, u));
			//构建分层图
			p[u].push_back(make_pair(w, v));
			p[v].push_back(make_pair(w, u));
			p[u+n].push_back(make_pair(w, v+n));
			p[v+n].push_back(make_pair(w, u+n));
			p[u+2*n].push_back(make_pair(w, v+2*n));
			p[v+2*n].push_back(make_pair(w, u+2*n));
		}
		else{
			//各层间连边
			p[u].push_back(make_pair(w, v+n));
			p[v].push_back(make_pair(w, u+n));
			p[u+n].push_back((make_pair(w, v+2*n)));
			p[v+n].push_back((make_pair(w, u+2*n)));
		} 
	}
	dij1(), dij2();
	cout << d_q[n]-min(min(d_p[3*n], d_p[2*n]), d_p[n]);
    return 0;
}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值