1.题目
题目链接 点这儿!
2.解决方法
题目可以抽象为一张无向网,给定的是手续费百分比,边权值可以据此改为扣掉手续费后所剩下的钱的百分比(eg:a与b之间手续费比例为3%,则金钱缩水为0.97)这张无向网,从源点到终点,根据题目要求是要找一条边权乘积最大的路径(具体解释在代码注释部分)乘积最大问题,可以转化为最短路径问题。
3.代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN=2010;
double g[MAXN][MAXN],dist[MAXN];
int n,m,A,B;
bool st[MAXN];
void dijkstra()//朴素dijkstra O(n^2)
{
dist[A]=1;
for(int i=1;i<=n;i++){
int t=-1;
for(int j=1;j<=n;j++)
if(!st[j]&&(t==-1||dist[t]<dist[j]))
t=j;
st[t]=true;
for(int j=1;j<=n;j++)
dist[j]=max(dist[j],dist[t]*g[t][j]);
}
}
int main(void)
{
cin>>n>>m;
//乘积最大问题,找到一条源点到终点权值乘积最大的路径
//最短路问题变形,dist的含义是从源点到每个点的最大权值乘积
//dist[j]=dist[j]+w[i]能否直接变成dist[j]=dist[t]*w[i]?
//是可以的
//dist[T]=dist[S]*w1*w2*...*wn可以通过两边同时取对数得到log(dist[T])=log(dist[S])+log(w1)+log(w2)+...+log(wn)
//两边同时取反,也就是对数和部分要达到最小值,左边的-log(dist[T])才能达到最大
//只有当0<=w[i]<=1时,log(w[i])<=0,取反后不会出现负值(即不会出现负权边),才能使用dijkstra算法,否则只能用spfa算法
for(int i=0;i<m;i++){
int a,b,c;
cin>>a>>b>>c;
double d=(100.0-c)/100;
g[a][b]=g[b][a]=max(g[a][b],d);
}
cin>>A>>B;
dijkstra();
printf("%.8lf\n",100.0/dist[B]);
return 0;
}