由于之前不会堆优化版本的 d i j s t r a dijstra dijstra,只会 s p f a spfa spfa算法,然后补题的时候想着用 s p f a spfa spfa算法过,没想到被卡了,所以去学了一手 d i j s t r a dijstra dijstra
这里讲一下两种算法的时间复杂度:
s
p
f
a
:
spfa:
spfa:核心思想
b
f
s
bfs
bfs,时间复杂度,不好证明,这算法写起来挺简单的,跑随机图飞快,但出题人刻意卡的话,那这个算法就不行了。
d
i
j
s
t
r
a
dijstra
dijstra: 核心思想贪心,时间复杂度
O
n
(
l
o
g
n
)
On(logn)
On(logn),用了优先队列,优化了普通
d
i
j
s
t
r
a
dijstra
dijstra找最小点距的位置
D e l i v e r t h e C a k e Deliver the Cake DelivertheCake
思路:
由于有
M
M
M的存在,图的就出现了多种可能性,所以我们需要把这些可能性考虑出来,然后将
M
M
M点拆开,然后建图,
M
M
M有
L
R
L R
LR两种可能,所以我们就需要考虑当
M
M
M为
L
∣
R
L|R
L∣R时,图的边权值了,这里我们可以将
M
M
M为
R
R
R时的点映射为
R
(
u
)
+
n
R(u)+n
R(u)+n,然后还有一种情况,若起始点为
M
M
M,或终点为
M
M
M时,我们将起始点设置为
0
0
0,终点设置为
(
2
n
+
1
)
(2n+1)
(2n+1),这样就不会影响拆点。
拆点代码:
if ((dir[u] == 'L' && dir[v] == 'R') || (dir[u] == 'R' && dir[v] == 'L'))
addT(u, v, w + x);
else if ((dir[u] == 'L' && dir[v] == 'L') || (dir[u] == 'R' && dir[v] == 'R'))
addT(u, v, w);
else if (dir[u] == 'M' && dir[v] == 'L')
addT(u, v, w), addT(u + n, v, w + x);
else if (dir[u] == 'M' && dir[v] == 'R')
addT(u + n, v, w), addT(u, v, w + x);
else if (dir[u] == 'L' && dir[v] == 'M')
addT(u, v, w), addT(u, v + n, w + x);
else if (dir[u] == 'R' && dir[v] == 'M')
addT(u, v + n, w), addT(u, v, w + x);
else if ((dir[u] == 'M' && dir[v] == 'M'))
addT(u, v, w), addT(u + n, v + n, w), addT(u, v + n, w + x), addT(u + n, v, w + x);
参考代码:
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <ctime>
#include <cstring>
#include <cstdlib>
#include <math.h>
using namespace std;
//typedef long long ll;
#define int long long
const int N = 1e3 + 5;
const int maxn = 2e6 + 20;
const int mod = 1e9 + 7;
int inv[maxn], dp[maxn], vis[maxn], dis[maxn];
vector<int> vec;
typedef pair<int, int> p;
int max(int a, int b) { return a > b ? a : b; }
int min(int a, int b) { return a < b ? a : b; }
int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
int lcm(int a, int b) { return a * b / gcd(a, b); }
struct node
{
int v, w, nex;
} edge[maxn];
int cnt, head[maxn], x, s, t, n, m;
char dir[maxn];
priority_queue<p, vector<p>, greater<p> > q;
void add(int u, int v, int w)
{
edge[cnt].w = w, edge[cnt].v = v, edge[cnt].nex = head[u];
head[u] = cnt++;
}
void addT(int u, int v, int w)
{
add(u, v, w), add(v, u, w);
}
void dij()
{
memset(vis, 0, sizeof vis);
memset(dis, 0x3f3f3f3f, sizeof dis);
if (dir[s] == 'M')
q.push({0, 0}), dis[0] = 0;
else
q.push({0, s}), dis[s] = 0;
while (!q.empty())
{
p t = q.top();
q.pop();
int u = t.second;
if (vis[u])
continue;
vis[u] = 1;
for (int i = head[u]; ~i; i = edge[i].nex)
{
int v = edge[i].v, w = edge[i].w;
if (dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
q.push({dis[v], v});
}
}
}
if (dir[t] == 'M')
cout << dis[2 * n + 1] << endl;
else
cout << dis[t] << endl;
}
void init()
{
cnt = 0;
memset(head, -1, sizeof head);
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int q, u, v, w;
cin >> q;
while (q--)
{
init();
cin >> n >> m >> s >> t >> x;
cin >> (dir + 1);
if (dir[s] == 'M')
addT(s, 0, 0), addT(0, s + n, 0);
if (dir[t] == 'M')
addT(t, 2 * n + 1, 0), addT(t + n, 2 * n + 1, 0);
for (int i = 1; i <= m; i++)
{
cin >> u >> v >> w;
if ((dir[u] == 'L' && dir[v] == 'R') || (dir[u] == 'R' && dir[v] == 'L'))
addT(u, v, w + x);
else if ((dir[u] == 'L' && dir[v] == 'L') || (dir[u] == 'R' && dir[v] == 'R'))
addT(u, v, w);
else if (dir[u] == 'M' && dir[v] == 'L')
addT(u, v, w), addT(u + n, v, w + x);
else if (dir[u] == 'M' && dir[v] == 'R')
addT(u + n, v, w), addT(u, v, w + x);
else if (dir[u] == 'L' && dir[v] == 'M')
addT(u, v, w), addT(u, v + n, w + x);
else if (dir[u] == 'R' && dir[v] == 'M')
addT(u, v + n, w), addT(u, v, w + x);
else if ((dir[u] == 'M' && dir[v] == 'M'))
addT(u, v, w), addT(u + n, v + n, w), addT(u, v + n, w + x), addT(u + n, v, w + x);
}
dij();
}
}