某市有 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;
}