题意:
给 定 一 个 n 个 点 , m 条 边 的 无 向 带 权 图 , 给定一个n个点,m条边的无向带权图, 给定一个n个点,m条边的无向带权图,
点 的 类 型 分 为 三 种 : L , R , M 点的类型分为三种:L,R,M 点的类型分为三种:L,R,M
到 达 L / R 点 时 必 须 保 持 状 态 L / R , 在 M 点 可 以 是 任 意 状 态 。 到达L/R点时必须保持状态L/R,在M点可以是任意状态。 到达L/R点时必须保持状态L/R,在M点可以是任意状态。
从 状 态 L / R 切 换 至 R / L 需 要 的 花 费 为 x , 从状态L/R切换至R/L需要的花费为x, 从状态L/R切换至R/L需要的花费为x,
现 计 算 从 s 点 到 t 点 的 最 少 花 费 是 多 少 。 现计算从s点到t点的最少花费是多少。 现计算从s点到t点的最少花费是多少。
输入:
T 组 测 试 数 据 , T组测试数据, T组测试数据,
首 行 包 含 五 个 正 整 数 : n , m , s , t , x , 首行包含五个正整数:n,m,s,t,x, 首行包含五个正整数:n,m,s,t,x,
接 着 一 行 长 度 为 n 的 字 符 串 , 依 次 表 示 每 个 点 的 类 型 , 接着一行长度为n的字符串,依次表示每个点的类型, 接着一行长度为n的字符串,依次表示每个点的类型,
最 后 m 行 , 每 行 包 括 三 个 正 整 数 a i , b i , d i , 表 示 点 a i 和 b i 之 间 有 一 条 权 值 为 d i 的 边 。 最后m行,每行包括三个正整数a_i,b_i,d_i,表示点a_i和b_i之间有一条权值为d_i的边。 最后m行,每行包括三个正整数ai,bi,di,表示点ai和bi之间有一条权值为di的边。
输出:
一 个 正 整 数 , 表 示 从 s 点 到 t 点 的 最 少 花 费 。 一个正整数,表示从s点到t点的最少花费。 一个正整数,表示从s点到t点的最少花费。
Sample Input
1
3 3 1 3 100
LRM
1 2 10
2 3 10
1 3 100
Sample Output
100
数据范围:
1 ≤ T ≤ 100 , 1 ≤ n ≤ 1 0 5 , 1 ≤ m ≤ 2 × 1 0 5 , 1 ≤ x ≤ 1 0 9 , 1 ≤ d i ≤ 1 0 9 1≤T≤100,1≤n≤10^5,1≤m≤2×10^5,1≤x≤10^9,1≤d_i≤10^9 1≤T≤100,1≤n≤105,1≤m≤2×105,1≤x≤109,1≤di≤109
The sum of n in all test cases doesn’t exceed 2×105. The sum of m doesn’t exceed 4×105.
分析:
本 题 由 于 存 在 M 类 型 的 点 , 造 成 了 两 点 之 间 代 价 的 不 确 定 。 本题由于存在M类型的点,造成了两点之间代价的不确定。 本题由于存在M类型的点,造成了两点之间代价的不确定。
若 两 点 的 类 型 不 同 , 一 个 是 L , 一 个 是 R , 那 么 经 过 这 两 点 之 间 的 边 , 需 要 额 外 的 代 价 x , 若两点的类型不同,一个是L,一个是R,那么经过这两点之间的边,需要额外的代价x, 若两点的类型不同,一个是L,一个是R,那么经过这两点之间的边,需要额外的代价x,
我 们 将 代 价 x 累 加 到 边 权 上 去 。 我们将代价x累加到边权上去。 我们将代价x累加到边权上去。
对 于 M 类 型 的 点 u , 我 们 将 其 拆 分 成 两 个 点 来 L 和 R 来 看 待 。 对于M类型的点u,我们将其拆分成两个点来L和R来看待。 对于M类型的点u,我们将其拆分成两个点来L和R来看待。
如何拆点?
可 以 通 过 增 加 偏 移 量 的 方 法 , 将 编 号 u 映 射 为 L 类 型 的 点 , 编 号 u + n 映 射 为 R 类 型 的 点 。 可以通过增加偏移量的方法,将编号u映射为L类型的点,编号u+n映射为R类型的点。 可以通过增加偏移量的方法,将编号u映射为L类型的点,编号u+n映射为R类型的点。
那 么 对 于 任 意 两 个 相 邻 的 点 u 和 v , 设 它 们 之 间 的 边 权 为 w , 共 有 3 × 3 = 9 种 建 边 的 可 能 : 那么对于任意两个相邻的点u和v,设它们之间的边权为w,共有3×3=9种建边的可能: 那么对于任意两个相邻的点u和v,设它们之间的边权为w,共有3×3=9种建边的可能:
① 、 u 和 v 的 类 型 均 为 L 或 均 为 R : 在 u 和 v 之 间 建 一 条 权 值 为 w 的 无 向 边 。 ①、u和v的类型均为L或均为R:在u和v之间建一条权值为w的无向边。 ①、u和v的类型均为L或均为R:在u和v之间建一条权值为w的无向边。
② 、 u 和 v 的 类 型 一 个 为 L , 另 一 个 为 R : 在 u 和 v 之 间 建 一 条 权 值 为 w + x 的 无 向 边 。 ②、u和v的类型一个为L,另一个为R:在u和v之间建一条权值为w+x的无向边。 ②、u和v的类型一个为L,另一个为R:在u和v之间建一条权值为w+x的无向边。
③ 、 u 为 L , v 为 M : 在 u 和 v 之 间 建 立 权 值 为 w 的 无 向 边 , u 和 v + n 之 间 建 立 权 值 为 w + x 的 无 向 边 。 ③、u为L,v为M:在u和v之间建立权值为w的无向边,u和v+n之间建立权值为w+x的无向边。 ③、u为L,v为M:在u和v之间建立权值为w的无向边,u和v+n之间建立权值为w+x的无向边。
④ 、 u 为 M , v 为 L : 在 u 和 v 之 间 建 立 权 值 为 w 的 无 向 边 , u + n 和 v 之 间 建 立 权 值 为 w + x 的 无 向 边 。 ④、u为M,v为L:在u和v之间建立权值为w的无向边,u+n和v之间建立权值为w+x的无向边。 ④、u为M,v为L:在u和v之间建立权值为w的无向边,u+n和v之间建立权值为w+x的无向边。
⑤ 、 u 为 R , v 为 M : 在 u 和 v 之 间 建 立 权 值 为 w + x 的 无 向 边 , u 和 v + n 之 间 建 立 权 值 为 w 的 无 向 边 。 ⑤、u为R,v为M:在u和v之间建立权值为w+x的无向边,u和v+n之间建立权值为w的无向边。 ⑤、u为R,v为M:在u和v之间建立权值为w+x的无向边,u和v+n之间建立权值为w的无向边。
⑥ 、 u 为 M , v 为 R : 在 u 和 v 之 间 建 立 权 值 为 w + x 的 无 向 边 , u + n 和 v 之 间 建 立 权 值 为 w 的 无 向 边 。 ⑥、u为M,v为R:在u和v之间建立权值为w+x的无向边,u+n和v之间建立权值为w的无向边。 ⑥、u为M,v为R:在u和v之间建立权值为w+x的无向边,u+n和v之间建立权值为w的无向边。
⑦ 、 u 为 M , v 为 M : ⑦、u为M,v为M: ⑦、u为M,v为M:
在 u 和 v 之 间 建 立 权 值 为 w 的 无 向 边 , u 和 v + n 之 间 建 立 权 值 为 w + x 的 无 向 边 。 \qquad在u和v之间建立权值为w的无向边,u和v+n之间建立权值为w+x的无向边。 在u和v之间建立权值为w的无向边,u和v+n之间建立权值为w+x的无向边。
在 u + n 和 v 之 间 建 立 权 值 为 w + x 的 无 向 边 , u + n 和 v + n 之 间 建 立 权 值 为 w 的 无 向 边 。 \qquad在u+n和v之间建立权值为w+x的无向边,u+n和v+n之间建立权值为w的无向边。 在u+n和v之间建立权值为w+x的无向边,u+n和v+n之间建立权值为w的无向边。
注意:
当 起 点 或 终 点 是 M 类 型 的 点 时 , 起 点 或 终 点 会 有 两 个 。 当起点或终点是M类型的点时,起点或终点会有两个。 当起点或终点是M类型的点时,起点或终点会有两个。
此 时 可 建 立 虚 拟 源 点 , 与 起 点 或 终 点 之 间 连 一 条 长 度 为 0 的 边 即 可 。 此时可建立虚拟源点,与起点或终点之间连一条长度为0的边即可。 此时可建立虚拟源点,与起点或终点之间连一条长度为0的边即可。
起 点 可 以 取 0 号 虚 拟 源 点 , 终 点 可 取 2 n + 1 号 虚 拟 源 点 ( 因 为 拆 点 将 右 点 都 增 加 了 n 的 偏 移 量 ) 。 起点可以取0号虚拟源点,终点可取2n+1号虚拟源点(因为拆点将右点都增加了n的偏移量)。 起点可以取0号虚拟源点,终点可取2n+1号虚拟源点(因为拆点将右点都增加了n的偏移量)。
建 完 图 后 跑 一 遍 d i j k s t r a 算 法 即 可 。 建完图后跑一遍dijkstra算法即可。 建完图后跑一遍dijkstra算法即可。
代码:
#include
#include
#include
#include
#include
#include
#define ll long long
#define P pair
#define x first
#define y second
using namespace std;
const int N=2e5+10, M=2e6+10, inf=0x3f3f3f3f;
int T,n,m,s,t,x;
int e[M],ne[M],w[M],h[N],idx;
char str[N];
ll dis[N];
bool st[N];
void add(int a,int b,int c)
{
e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
int dijkstra()
{
memset(st,false,sizeof st);
memset(dis,0x3f,sizeof dis);
if(str[s]=='M') dis[0]=0;
else dis[s]=0;
priority_queue<P,vector<P>,greater<P>> heap;
if(str[s]=='M') heap.push({0,0});
else heap.push({0,s});
while(heap.size())
{
P t=heap.top();
heap.pop();
int id=t.second;
if(st[id]) continue;
st[id]=true;
for(int i=h[id];~i;i=ne[i])
{
int j=e[i];
if(dis[j]>dis[id]+w[i])
{
dis[j]=dis[id]+w[i];
heap.push({dis[j],j});
}
}
}
if(str[t]=='M') return dis[2*n+1];
return dis[t];
}
int main()
{
scanf("%d",&T);
while(T--)
{
idx=0;
memset(h,-1,sizeof h);
scanf("%d%d%d%d%d",&n,&m,&s,&t,&x);
scanf("%s",str+1);
if(str[s]=='M')
{
add(0,s,0), add(s,0,0);
add(0,s+n,0), add(s+n,0,0);
}
if(str[t]=='M')
{
add(2*n+1,t,0), add(t,2*n+1,0);
add(2*n+1,t+n,0), add(t+n,2*n+1,0);
}
int a,b,c;
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&a,&b,&c);
if((str[a]=='L'&&str[b]=='R') || (str[a]=='R'&&str[b]=='L'))
{
add(a,b,c+x), add(b,a,c+x); //LR or RL
}
else if((str[a]=='L'&&str[b]=='L') || (str[a]=='R'&&str[b]=='R'))
{
add(a,b,c), add(b,a,c); //LL or RR
}
else if(str[a]=='L'&&str[b]=='M')
{
add(a,b,c), add(b,a,c); // LL
add(a,n+b,c+x), add(n+b,a,c+x); //LR
}
else if(str[a]=='M'&&str[b]=='L')
{
add(a,b,c), add(b,a,c); //LL
add(a+n,b,c+x), add(b,a+n,c+x); //RL
}
else if(str[a]=='R'&&str[b]=='M')
{
add(a,b,c+x), add(b,a,c+x); //RL
add(a,n+b,c), add(n+b,a,c); //RR
}
else if(str[a]=='M'&&str[b]=='R')
{
add(a,b,c+x), add(b,a,c+x); //LR
add(a+n,b,c), add(b,a+n,c); //RR
}
else if(str[a]=='M'&&str[b]=='M')
{
add(a,b,c), add(b,a,c); //LL
add(a,b+n,c+x), add(b+n,a,c+x); //LR
add(a+n,b,c+x), add(b,a+n,c+x); //RL
add(a+n,b+n,c), add(b+n,a+n,c); //RR
}
}
printf("%lld\n",dijkstra());
}
return 0;
}