最短路,链式向前星,循环dp,分层图
题意:
分析:
这题不难,循环dp问题而已(分层图)
正好最近我认真研究过,所以当时在赛场上的时候我还是很有自信能做出来的。
思路如下,我们添加一维构造循环dp。d[i][j]为节点i在j状态下距离s的最短距离!!!
我们很容易能推出其动态转移方程:
d[i][j] =
min(d[k][j] k为i邻节点,且k与i同类型或者为M)
min(d[k][(j+1)%2] k为i邻节点,且k与i类型相反或为M)
二者取小
很容易的发现这是个典型的循环dp,我们使用松弛操作对其进行破解。使用dijstra
具体原理请看我的另一篇博客:
https://blog.nowcoder.net/n/8316b13c345d49b08b2ae7f41c49da71
代码如下:
#include<iostream> #include<algorithm> #include<queue> #include<cassert> #include<string> #include<functional> #include<vector> using namespace std; typedef long long ll; const ll max_n = 2e5 + 100; const ll inf = 1e18; typedef pair<int, int> pii; typedef pair<ll, pii> pli; struct edge { int to; ll cost; int next = false; }E[4 * max_n]; string a; ll d[max_n][2]; int n, m, s, e; ll x; char type[2] = { 'L','R' }; int cnt = 1; ll head[max_n]; void add(ll from, ll to, ll w) { E[cnt].to = to; E[cnt].cost = w; E[cnt].next = head[from]; head[from] = cnt++; } void dijstra(int s,int t) { for (int i = 1;i <= n;i++) d[i][0] = d[i][1] = inf; if (a[s - 1] == 'L' && t == 1)return; if (a[s - 1] == 'R' && t == 0)return; priority_queue<pli,vector<pli>,greater<pli>> que; d[s][t] = 0;que.push({ d[s][t],{s,t} }); while (!que.empty()) { pli p = que.top();que.pop(); pii pos = p.second;ll dist = p.first; if (dist > d[pos.first][pos.second]) continue; char ch = type[pos.second]; for (int i = head[pos.first];i;i = E[i].next) { edge e = E[i]; if (a[e.to - 1] == ch || a[e.to - 1] == 'M') { if (d[e.to][pos.second] > dist + e.cost) { d[e.to][pos.second] = dist + e.cost; que.push({ d[e.to][pos.second],{e.to,pos.second} }); } } if (a[e.to - 1] != ch || a[e.to - 1] == 'M') { if (d[e.to][(pos.second + 1) & 1] > dist + e.cost + x) { d[e.to][(pos.second + 1) & 1] = dist + e.cost + x; que.push({ d[e.to][(pos.second + 1) & 1],{e.to,(pos.second + 1) & 1} }); } } } } } int main() { ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); int T;cin >> T; while (T--) { cin >> n >> m >> s >> e >> x; for (int i = 0;i <= n;i++) head[i] = 0; cin >> a; for (int i = 1;i <= m;i++) { int u, v; ll w; cin >> u >> v >> w; add(u, v, w); add(v, u, w); } ll ans = inf; if (a[s - 1] == type[0] || a[s - 1] == 'M') { dijstra(s, 0); ll ans1 = min(d[e][1], d[e][0]); ans = min(ans, ans1); } if (a[s - 1] == type[1] || a[s - 1] == 'M') { dijstra(s, 1); ll ans1 = min(d[e][1], d[e][0]); ans = min(ans, ans1); } cout << ans << endl; } }
当然,你也可以使用分层图,但我个人认为分层图并没有循环dp的想法系统直接
另外,这题卡vector我之前只会用vector。赛场上第一次用前向链式星,细节错了。真的可惜