AcWing 1126. 最小花费
题目传送门
一、SPFA
#include
using namespace std;
const int N = 2010; //点数,看的出来,点数不多,采用邻接矩阵也OK
const int M = 2e5 + 10; //边数
//如果本题想要卡SPFA,也可以卡的死死的,因为最差的是O(n*m)=4e8
int n; // n个节点
int m; // m条边
double dist[N]; //从A点出发,到达每个点的最大距离
bool st[N]; //点i是不是已经进入队列
//链接前向星,注意double类型
int h[N], e[M], ne[M], idx;
double w[M];
void add(int a, int b, double c) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
//从start出发
void spfa(int start) {
queue q;
dist[start] = 1; // 剩余的百分比(想像一下手机电池,目前是100%状态出发)
q.push(start);
st[start] = true; //标识在队列中
while (q.size()) {
int u = q.front(); //取出当前要处理的节点
q.pop();
st[u] = false; // u节点出队列
//枚举u节点的每一条出边
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i]; //对方节点号j
double a = 1 - w[i]; // 100%减去消耗率,得到本路径的剩余率,需要与带过的数据连乘
if (dist[j] < dist[u] * a) { //利用u更新j的路径最大值
dist[j] = dist[u] * a;
if (!st[j]) {
st[j] = true;
q.push(j);
}
}
}
}
}
int main() {
memset(h, -1, sizeof h);
cin >> n >> m;
while (m--) {
int a, b, c;
cin >> a >> b >> c;
double w = c * 0.01; //消耗的百分比,举例:从A->B的消耗百分比为2%
add(a, b, w), add(b, a, w);
}
int A, B;
cin >> A >> B;
spfa(A);
// ∵ x *w1*w2*w3* ... = 100
// ∴ x = 100/(w1 * w2 * w3 * ...)
// dist[B]装的就是从A点出发,到B点的 w1*w2*w3*...的连乘积
printf("%.8lf\n", 100 / dist[B]);
return 0;
}
二、Dijkstra+堆优化
#include
using namespace std;
const int N = 2010; //点数,看的出来,点数不多,采用邻接矩阵也OK
const int M = 2e5 + 10; //边数
//如果本题想要卡SPFA,也可以卡的死死的,因为最差的是O(n*m)=4e8
typedef pair PDI;
int n; // n个节点
int m; // m条边
double dist[N]; //从A点出发,到达每个点的最大距离
bool st[N]; //点i是不是已经进入队列
int h[N], e[M], ne[M], idx;
double w[M];
void add(int a, int b, double c) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
void dijkstra(int start) {
priority_queue q; //最长路径,用大根堆
dist[start] = 1; //剩余的百分比(想像一下手机电池,目前是100%状态出发)
q.push({1, start}); //大根堆,按距离最大到小排序
while (q.size()) {
auto t = q.top();
q.pop();
int u = t.second;
if (!st[u]) {
st[u] = true;
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
double a = 1 - w[i]; // 100%减去消耗率,得到本路径的剩余率,需要与带过的数据连乘
if (dist[j] < dist[u] * a) { //利用u更新j的路径最大值
dist[j] = dist[u] * a;
q.push({dist[j], j});
}
}
}
}
}
int main() {
memset(h, -1, sizeof h);
cin >> n >> m;
while (m--) {
int a, b, c;
cin >> a >> b >> c;
double w = c * 0.01; //消耗的百分比,举例:从A->B的消耗百分比为2%
add(a, b, w), add(b, a, w);
}
int A, B;
cin >> A >> B;
dijkstra(A);
// ∵ x *w1*w2*w3* ... = 100
// ∴ x = 100/(w1 * w2 * w3 * ...)
// dist[B]装的就是从A点出发,到B点的 w1*w2*w3*...的连乘积
printf("%.8lf\n", 100 / dist[B]);
return 0;
}