在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;
}