题目
题目描述
Rinne 学到了一个新的奇妙的东西叫做动态图,这里的动态图的定义是边权可以随着操作而变动的图。
当我们在这个图上经过一条边的时候,这个图上所有边的边权都会发生变动。
定义变动函数 \(f(x) = \frac{1}{1-x}\) ,表示我们在图上走过一条边后,图的边权变动情况。
这里指的“图的变动”的意思是将每条边的边权代入上函数,得到的值即为该次变动后的边权。
现在 Rinne 想要知道,在这个变动的图上从 1 到 n 的最短路径。
因为 Rinne 不喜欢负数,所以她只需要你输出经过的边权权值绝对值之和最小的那个值就可以了。
输出答案保留三位小数。
输入描述
第一行两个正整数 N,M,表示这个动态图的点数和边数。
接下来 M 行,每行三个正整数 u,v,w,表示存在一条连接点 u,v 的无向边,且初始权值为 w。
输出描述
如果能到达的话,输出边权绝对值之和最小的答案,保留三位小数。
否则请输出 -1。
示例1
输入
3 3
1 2 2
2 3 2
3 1 3
输出
3.000
说明
走 \(1 \to 2 \to 3\) ,总花费 \(2 + |\frac{1}{1-2}| = 3\)
备注
\(n \leq 100000,m \leq 300000,2 \leq x \leq 1000\)
题解
知识点:最短路。
注意到,边权是一个周期变化 \(|x|,|\frac{1}{1-x}|,|1-\frac{1}{x}|,|x|,\cdots\) 。因此我们保存一个周期的边权跑最短路,再给 \(dis\) 加一个维度记录不同边权下的最短路。
时间复杂度 \(O((n+m)\log m)\)
空间复杂度 \(O(n+m)\)
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
template<class T>
struct Graph {
struct edge {
int v, nxt;
T w;
};
int idx;
vector<int> h;
vector<edge> e;
Graph(int n, int m):idx(0), h(n + 1), e(m + 1) {}
void init(int n) {
idx = 0;
h.assign(n + 1, 0);
}
void add(int u, int v, const T &w) {
e[++idx] = edge{ v,h[u],w };
h[u] = idx;
}
};
const int N = 100000 + 7, M = 300000 + 7 << 1;
Graph<vector<double>> g(N, M);
int n, m;
bool vis[N][3];
double dis[N][3];
struct node {
int v, cnt;
double w;
friend bool operator<(const node &a, const node &b) {
return a.w > b.w;
}
};
priority_queue<node> pq;
double dijkstra(int st) {
for (int i = 1;i <= n;i++) dis[i][0] = dis[i][1] = dis[i][2] = 0x3f3f3f3f;
dis[st][0] = 0;
pq.push({ st,0,0 });
while (!pq.empty()) {
int u = pq.top().v, cnt = pq.top().cnt;
pq.pop();
if (u == n) return dis[u][cnt];
if (vis[u][cnt]) continue;
vis[u][cnt] = 1;
for (int i = g.h[u];i;i = g.e[i].nxt) {
int v = g.e[i].v;
double w = g.e[i].w[cnt];
if (dis[v][(cnt + 1) % 3] > dis[u][cnt] + w) {
dis[v][(cnt + 1) % 3] = dis[u][cnt] + w;
pq.push(node{ v,(cnt + 1) % 3,dis[v][(cnt + 1) % 3] });
}
}
}
return -1;
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> m;
for (int i = 1;i <= m;i++) {
int u, v;
double w;
cin >> u >> v >> w;
g.add(u, v, { w,abs(1 / (1 - w)),abs(1 - 1 / w) });
g.add(v, u, { w,abs(1 / (1 - w)),abs(1 - 1 / w) });
}
double ans = dijkstra(1);
if (ans < 0) cout << -1 << '\n';
else cout << fixed << setprecision(3) << ans << '\n';
return 0;
}
标签:cnt,Rinne,idx,int,Graph,边权,Dynamic,NC22600,dis
From: https://www.cnblogs.com/BlankYang/p/17027911.html