题目描述
在 n 个人中,某些人的银行账号之间可以互相转账。这些人之间转账的手续费各不相同。给定这些人之间转账时需要从转账金额里扣除百分之几的手续费,请问 A 最少需要多少钱使得转账后 B 收到 100 元。
输入描述
第一行输入两个正整数 n,m,分别表示总人数和可以互相转账的人的对数。
以下 m 行每行输入三个正整数 x,y,z,表示标号为 x 的人和标号为 y 的人之间互相转账需要扣除z%的手续费 (z<100)。
最后一行输入两个正整数 A,B。数据保证 A 与 B 之间可以直接或间接地转账。
输出描述
输出 A 使得 B 到账 100 元最少需要的总费用。精确到小数点后 8 位。
样例输入
3 3 1 2 1 2 3 2 1 3 3 1 3
样例输出
103.07153164
首先要先理解题目,从一号转到三号有两种方法,1->2->3或者1->3,这里的z分别为1,2,3,代表1%,2%,3%,那么转账后剩下的就分别是99%,98%,97%,那么,方法一就能剩下99%乘98%等于97.02%,方法二剩下97%,方法一剩的多,就学用,那么那一百元就是转账钱数的97.02%,转账钱数就是100/97.02%约等于103.07153164( 八位小数 )。
好,现在题目理解了,开始理思路,所以这道题要求的,就是1到n路径边权的乘积最大值,最后用一百除以这个最大值,得出答案,那这道题就很好解了,在dijkstra的基础上,改优先队列的重载函数,改dis数组初始化,改更新条件,就行了
#include<bits/stdc++.h>
using namespace std;
const int N=2005;
struct node{
int to;
double val;
friend bool operator <(node a,node b){
return a.val<b.val;
}
};
vector<node>a[N];
int n,m;
priority_queue<node>q;
double dis[N];
int vis[N];
int st,ed;
void dij(){
for(int i=1;i<=n;i++)dis[i]=0;//因为是最大值,所以赋值为零
dis[st]=1;
q.push(node{st,1});
while(!q.empty()){
int x=q.top().to;
q.pop();
if(vis[x]==1)continue;
vis[x]=1;
for(int i=0;i<a[x].size();i++){
int v=a[x][i].to;
double w=a[x][i].val;
if(dis[v]<dis[x]*w){//注意是小于
dis[v]=dis[x]*w;
if(vis[v]==0){
q.push(node{v,dis[v]});
}
}
}
}
}
signed main(){
scanf("%d%d",&n,&m);
int x,y,z;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
double xx=1.0*(100-z)/100;
a[x].push_back(node{y,xx});
a[y].push_back(node{x,xx});
}
scanf("%d%d",&st,&ed);
dij();
printf("%.8lf",100.0/dis[ed]);
}