由于之前不会堆优化版本的 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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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();
}
}