[图论]最小花费

Leona ·
更新时间:2024-11-14
· 629 次阅读

最小花费 目录最小花费题目描述输入格式输出格式输入输出解析代码 题目描述

在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

解析

又是一道最短路的水题,只需注意题目给的百分比的运算,其他的就是套我们的模板。
本题解用的是Dijkstra算法,以下为Dijkstra算法的简单描述。
Dijkstra用来计算从一个点到其他所有点的最短路径的算法,是一种单源最短路径算法。也就是说,只能计算起点只有一个的情况。
Dijkstra的时间复杂度是O (N2),它不能处理存在负边权的情况。
算法描述:

设起点为s,dis[v]表示从s到v的最短路径,pre[v]为v的前驱节点,用来输出路径。 初始化:dis[v]=∞(v≠s); dis[s]=0; pre[s]=0; For (i = 1; i <= n ; i++) 1.在没有被访问过的点中找一个顶点u使得dis[u]是最小的。 2.u标记为已确定最短路径 3.For 与u相连的每个未确定最短路径的顶点v if (dis[u]+w[u][v] < dis[v]) { dis[v] = dis[u] + w[u][v]; pre[v] = u; } 算法结束:dis[v]为s到v的最短距离;pre[v]为v的前驱节点,用来输出路径。

Dijkstra算法扩展

代码 #include #include #include using namespace std; int n,m,u[2005],t1,t2; double b[2005],a[2005][2005]; int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int xxx,ooo,ooxx; scanf("%d%d%d",&xxx,&ooo,&ooxx); a[xxx][ooo]=a[ooo][xxx]=(100-ooxx)/100.0; //计算百分比 } scanf("%d%d",&t1,&t2); for(int i=1;i<=n;i++) b[i]=a[t1][i]; u[t1]=1; //标记初始点t1 b[t1]=1; //自己到自己的代价为 100% for(int i=1;i<=n-1;i++){ int o=0; for(int j=1;jb[o]) //与平常不同的,因为这里是比谁的百分比的 o=j; //找到最小点并标记 } u[o]=1; //标记u[o]为白点 for(int j=1;jb[j]) //注意,这里是b[o]*a[o][j],因为计算的是百分比,所以用乘法。大于号就不解释了,同上 b[j]=b[o]*a[o][j]; //更新百分比 } } printf("%.8lf",100/b[t2]); //反过来用100来除以百分比 return 0; }
作者:ssl_ljh



图论

需要 登录 后方可回复, 如果你还没有账号请 注册新账号