移动迷宫题解
【n\le 10 】
给爆搜的。不过搜索应该也不好写。
【所有边权相等】
这个题的难点其实就在于有可能通过往回走把原本的下一步变小。但是当所有边权相等的时候,往回走本身就要花费 "原本下一步" 的权值,再走回来必然严格更差。
所以不会走回头路。于是只需要正常跑最短路即可。
【满分做法】
样例二给了提示:
观察发现,
既然如此,我们直接分层图,将图分成三层。令
对于一条边
Fun Facts: 这题本来模数是 实在太伟大了
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 3e5 + 5;
const ll MOD = 754974721;
ll fpow(ll a, ll b, ll p) {
ll mul = 1;
while (b) {
if (b & 1)
mul = mul * a % p;
a = a * a % p;
b >>= 1;
}
return mul;
}
long long inv(long long x, long long mod) { // 计算 x 在模 mod 下的逆元
x = (x % mod + mod) % mod;
return fpow(x, mod - 2, mod);
}
ll n, m;
struct Edge {
ll to, val;
Edge(ll t = 0, ll v = 0) {
to = t, val = v;
}
};
vector<Edge> e[N];
void addedge(ll u, ll v, ll w) {
ll ww = inv(1 - w, MOD), www = inv(1 - ww, MOD);
e[u].push_back(Edge(v + n, w));
e[u + n].push_back(Edge(v + 2 * n, ww));
e[u + 2 * n].push_back(Edge(v, www));
e[v].push_back(Edge(u + n, w));
e[v + n].push_back(Edge(u + 2 * n, ww));
e[v + 2 * n].push_back(Edge(u, www));
}
ll dist[N];
bool vis[N];
typedef pair<ll, ll> pii;
void dijkstra(ll s) {
priority_queue<pii, vector<pii>, greater<pii> > q;
memset(dist, 0x3f, sizeof dist);
memset(vis, false, sizeof vis);
dist[s] = 0;
q.push(make_pair(dist[s], s));
while (!q.empty()) {
ll h = q.top().second;
q.pop();
if (vis[h])
continue;
vis[h] = true;
for (ll i = 0; i < e[h].size(); i++)
if (dist[e[h][i].to] > dist[h] + e[h][i].val) {
dist[e[h][i].to] = dist[h] + e[h][i].val;
q.push(make_pair(dist[e[h][i].to], e[h][i].to));
}
}
}
int main() {
cin >> n >> m;
for (ll i = 1; i <= m; i++) {
ll u, v, w;
cin >> u >> v >> w;
addedge(u, v, w);
}
dijkstra(1);
cout << min(dist[n * 3], min(dist[n * 2], dist[n]));
return 0;
}