15th 【最短路 dijkstra】最小花费

                                                                                             最小花费

在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[i]=a[i][j]+f[i]


那么如何确定每个点的最短距离f[i]呢

贪心思路是很完美的

首先从起点开始,搜索到一个最近的点,比如是第k个点,那么f[k]一定是最优的了。

那么以k为中心点,对于其他所有点进行松弛操作,就是上一段的操作,

这样就一定有一个点被松弛到最优了 ,所以再从没有遍历的点中找到一个f[p]最小的p点,该点距离一定是最优值了,所以遍历该点

然后再以p为中心,进行松弛操作。。。。。


这里这题首先需要一个处理,把它变成百分比,也就是每条边的权值,总的结果越大越好。

这里需要注意,这个百分比是要乘的,最后用100除以实际的百分比就是要花的钱了!

#include   
#include   
#include   
#include   
#include 
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;  
}


你可能感兴趣的:(最短路)