最小花费
在n个人中,某些人的银行账号之间可以互相转账。这些人之间转账的手续费各不相同。给定这些人之间转账时需要从转账金额里扣除百分之几的手续费,请问A最少需要多少钱使得转账后B收到100元。
【输入文件】
第一行输入两个用空格隔开的正整数n和m,分别表示总人数和可以互相转账的人的对数。以下m行每行输入三个用空格隔开的正整数x,y,z,表示标号为x的人和标号为y的人之间互相转账需要扣除z%的手续费(z<100)。最后一行输入两个用空格隔开的正整数A和B。数据保证A与B之间可以直接或间接地转账。
【输出文件】
输出A使得B到账100元最少需要的总费用。精确到小数点后8位。
【约定】
对于所有数据,1<=n<=2000。
【样例输入】
3 3
1 2 1
2 3 2
1 3 3
1 3
【样例输出】
103.07153164
这是一道求最短路径的题目
我觉得迪杰斯特拉算法还是很好理解的。
用f[i]表示从起点到第i个点的最短距离。
那么以该点为中心穷举每个没有遍历点 如果 a[i][j]+f[i]<f[j]
那么就替换 F[i]=a[i][j]+f[i]
那么如何确定每个点的最短距离f[i]呢
贪心思路是很完美的
首先从起点开始,搜索到一个最近的点,比如是第k个点,那么f[k]一定是最优的了。
那么以k为中心点,对于其他所有点进行松弛操作,就是上一段的操作,
这样就一定有一个点被松弛到最优了 ,所以再从没有遍历的点中找到一个f[p]最小的p点,该点距离一定是最优值了,所以遍历该点
然后再以p为中心,进行松弛操作。。。。。
这里这题首先需要一个处理,把它变成百分比,也就是每条边的权值,总的结果越大越好。
这里需要注意,这个百分比是要乘的,最后用100除以实际的百分比就是要花的钱了!
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
int inf=-2147483647;
int n,m,p,q;
double a[2005][2005];
double f[2005];
int book[2005];
int main()
{ //freopen("test1.in","r",stdin);
//freopen("test1.out","w",stdout);
int x,y;
double z;
cin>>n>>m;
for(int i=1;i<=m;i++)
{cin>>x>>y>>z;
a[x][y]=1.00-z/100;
a[y][x]=a[x][y];
//printf("a[%d][%d]=a[%d][%d]=%.2f\n",x,y,y,x,a[x][y]);
}
cin>>p>>q;
book[p]=1;
for(int i=1;i<=n;i++) f[i]=a[p][i];
for(int i=2;i<=n;i++)
{ double mx=0;
int now;
for(int j=1;j<=n;j++)
if(book[j]!=1&&f[j]>mx)
{mx=f[j];
now=j;}//寻找点
book[now]=1;//标记为已遍历
for(int j=1;j<=n;j++)
if(f[now]*a[now][j]>f[j]&&book[j]!=1)
f[j]=f[now]*a[now][j];//松弛操作
}
printf("%.8f\n",100/f[q]);
return 0;
}