
题意:有m个点和n条路,点分为M,L,R三种类型,从L到R或者R到L都会花多于的时间x,而M不会,求从点s到点t花的最少时间。
思路:因为有M这种类型阻碍了直接使用Dijkstra算法,但可将M分为L和R两个点来解决,这样就构成一个新的图,利用Dijkstra算法来解决即可。
www.manongjc.com/detail/18-iowrqwislapwaoq.html
学习的是该链接中的代码,比起发的题解自己更容易理解些。
注意:要理解Dijkstra算法和点是怎样拆分的。
#include <bits/stdc++.h>
#include <stack>
#include <map>
#include <queue>
#include <cstring>
#include <algorithm>
#define fi first
#define se second
typedef long long ll;
using namespace std;
const int maxn = 2e5+10;
const int INF = 0x3f3f3f3f;
ll tcase,n,m,s,t,x,v[maxn];
char f[maxn];
struct shudui{
ll start,val;//起点和值
bool operator < (const shudui y) const{
return val > y.val;
}
}str1,str2;
priority_queue<shudui>r;//优先队列
vector<shudui>w[maxn];//变长数组
void add_edge(ll a,ll b,ll c)//连边
{
str2.start = b;
str2.val = c;
w[a].push_back(str2);
str2.start = a;
w[b].push_back(str2);
}
void JK(ll st){
memset(v,INF,sizeof(v));
v[st] = 0;
str1.start = st;
str1.val = 0;
r.push(str1);
while(!r.empty()){
ll x,y;
str1 = r.top();
r.pop();
x = str1.start;
y = str1.val;
if(v[x]<y) continue;
ll len = w[x].size();
for(ll i=0;i<len;i++){
str2 = w[x][i];
if(v[x]+str2.val<v[str2.start]){
v[str2.start]=v[x]+str2.val;
str1.start = str2.start;
str1.val = v[str2.start];
r.push(str1);
}
}
}
}
int main(){
scanf("%lld",&tcase);
while(tcase--){
scanf("%lld%lld%lld%lld%lld",&n,&m,&s,&t,&x);
for(ll i=0;i<=2*n;i++){
w[i].clear();//用前清空
}
scanf("%s",f+1); //输入路的类型
while(m--){
ll a,b,c;
scanf("%lld%lld%lld",&a,&b,&c);//输入起点,终点和长度
//将M类型的路分成两种L和R,然后分情况讨论
//①都为L或R
if(f[a]==f[b]&&(f[a]=='L'||f[b]=='R')){
add_edge(a,b,c);//为原长
}
//②一个为R,一个为L
else if(f[a]!=f[b]&&f[a]!='M'&&f[b]!='M'){
add_edge(a,b,c+x);//switch一次,长度为c+x
}
//③起点为L,终点为M,将M分为L和R
else if(f[a]=='L'&&f[b]=='M'){
add_edge(a,b,c);//当M为L
add_edge(a,b+n,c+x);//当M为R
}
//④起点为M,终点为L
else if(f[a]=='M'&&f[b]=='L'){
add_edge(a,b,c);//当M为L
add_edge(a+n,b,c+x);//当M为R
}
//⑤起点为R,终点为M
else if(f[a]=='R'&&f[b]=='M'){
add_edge(a,b,c+x);//当M为L
add_edge(a,b+n,c);//当M为R
}
//⑥起点为M,终点为R
else if(f[a]=='M'&&f[b]=='R'){
add_edge(a+n,b,c);//当M为R
add_edge(a,b,c+x);//当M为L
}
//当都为M,有四种走法
else {
add_edge(a,b,c);//M都为L
add_edge(a,b+n,c+x);//起点为L,终点为R
add_edge(a+n,b,c+x);//起点为R,终点为L
add_edge(a+n,b+n,c);//都为R
}
}
ll ans = 0;
if(f[s]=='M'){//s为起点
add_edge(0,s,0);//以L为起点
add_edge(0,s+n,0);//以M为起点
JK(0);
ans = min(v[t],v[t+n]);
}
else{
JK(s);
ans = min(v[t],v[t+n]);
}
printf("%lld\n",ans);
}
return 0;
}
本文介绍了一种改进的Dijkstra算法,用于解决包含特殊类型节点(M、L、R)的最短路径问题。通过拆分M类型节点,转化为标准图论问题,再运用Dijkstra算法求解。文章提供了详细的代码实现和解析。

被折叠的 条评论
为什么被折叠?



