假设初始金钱为N
,那么如果要在最后一个人的手里得到100
元,我们可以得到公式:
$$
N * (1 - z_1\\%) * (1 - z_2\\%) * … * (1 - z_n\\%) = 100
$$
这貌似是小学里的求有关利润问题的公式?我对着样例瞎推了半天。。
那么就可以得到:
$$
N = \cfrac{100}{(1 - z_1\\%) * (1 - z_2\\%) * … * (1 - z_n\\%)}
$$
所以我们要想使得N
尽可能小,那么就要让分母尽可能大才行,即让$(1 - z_1\\%) * (1 - z_2\\%) * … * (1 - z_n\\%)$尽可能的大,那么我们就可以用最短路算法来找到一条路径让分母最大。
需要注意的是:我们要使得分母最大,那么应该让每一项的$z_i\\%$越小才行,所以这里不能用小根堆了,应该改成大根堆,然后更新的时候用:dist[j] = (double) dist[var] * (1 - w[i] * 0.01)
,貌似spfa
不用考虑这些,我是dijkstra
爱好者hh。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
typedef pair<double, int> PDI;
const int N = 2010, M = 2e5 + 10;
int h[N], e[M], ne[M], idx;
double w[M];
bool st[N];
int n, m;
double dist[N];
void add(int a, int b, double c) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
void Dijkstra(int ts) {
memset(dist, 0, sizeof dist);
priority_queue<PDI, vector<PDI>> heap; //大根堆
heap.push({1, ts});
dist[ts] = 1;
while (heap.size()) {
auto t = heap.top();
heap.pop();
int var = t.second;
if (st[var]) continue;
st[var] = true;
for (int i = h[var]; i != -1; i = ne[i]) {
int j = e[i];
if (dist[j] < (double) dist[var] * (1 - w[i] * 0.01)) {
dist[j] = (double) dist[var] * (1 - w[i] * 0.01);
heap.push({dist[j], j});
}
}
}
}
int main() {
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
for (int i = 0; i < m; i++) {
int a, b;
double c;
scanf("%d%d%lf", &a, &b, &c);
add(a, b, c), add(b, a, c);
}
int ts, te;
scanf("%d%d", &ts, &te);
Dijkstra(ts);
printf("%.8lf", (double) 100 / dist[te]);
return 0;
}
哥,这样写是大根堆,我们这个写法要优先用数值大的去更新,错一个小时了就因为写的小根堆,吐了,气死
哦我打错了,hh,谢谢更正