= Vain学习(C/C++ acm算法 python Linux Golang)的个人网站 =

HDU 多校联赛第四场 Deliver the Cake

Posted on

由于之前不会堆优化版本的dijstra,只会spfa算法,然后补题的时候想着用spfa算法过,没想到被卡了,所以去学了一手dijstra

这里讲一下两种算法的时间复杂度:
spfa:核心思想 bfs,时间复杂度,不好证明,这算法写起来挺简单的,跑随机图飞快,但出题人刻意卡的话,那这个算法就不行了。
dijstra: 核心思想贪心,时间复杂度On(logn),用了优先队列,优化了普通dijstra找最小点距的位置

Deliver the Cake

思路:
由于有M的存在,图的就出现了多种可能性,所以我们需要把这些可能性考虑出来,然后将M点拆开,然后建图,M有L R两种可能,所以我们就需要考虑当M为L|R时,图的边权值了,这里我们可以将M为$R$时的点映射为R(u)+n,然后还有一种情况,若起始点为M,或终点为M时,我们将起始点设置为0,终点设置为(2n+1),这样就不会影响拆点。

拆点代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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);

参考代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#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();
}
}