[dijkstra 图论 最短路] 最小花费

今天给大家讲最小花费这道题目在这里插入图片描述

思路

题目大意就是现在给定一些人之间转账的要给的手续费,让你求出 a a a转账给 b b b的最小花费。
很显然,为了求出最小花费,又给定了一些人之间要给的手续费。 我们可以吧人看作点,两个人之间可以互相转账看作他们之间有一条路径,要给的手续费为这条路径的权值,那么这个问题就被简化成了一个图论问题。

由于要求最小话费,也就是最短路,所以在这张图中我们又要采用 d i j k s t r a dijkstra dijkstra算法。 但是接下来有几个问题请大家要注意一下。

q 1 q1 q1
由于他给的是手续费,但是在最短路过程中,我们不仅需要手续费,也需要他给了手续费剩下的钱数占总钱数的%几,所以在运算过程中要用 100 100 100%-手续费占总钱的百分比求出剩余钱数的%比
q 2 q2 q2
人之间的手续费是给的百分数,是占总钱数的百分比,所以我们在计算最短路的时候,要把加法改为乘法。
q 3 q3 q3
由于最终计算出来的是给完手续费之后,剩余的钱数,所以我们要用 剩余钱数 / / /最后剩余钱数占花费的百分比,即100/$剩余钱数占花费的百分比 来求出他所需要的最少花费。
q 4 q4 q4
由于我们求的是最小花费,而最小花费 = 100 / =100/ =100/剩余钱数占花费的百分比。所以我们需要让剩余钱数占花费的百分比越大,花费才越小。所以在这里,我们求的是最长路,而不是最短路。但是求最长路的方法仍然是 d i j k s t r a dijkstra dijkstra,只需要将符号和初始值变动一下即可。

代码

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int m,n,k1,k2;
int fst[500005];
int last[500005];
int vis[500005];
double dis[500005];//dis数组记得定义为double类型
int cnt;
struct xytsb
{
    int u,nxt;
    double v;
}arr[500005];
void adds(int r,int l,int w)
{
    arr[++cnt].u=l,arr[cnt].v=1.0-w/100.0,arr[cnt].nxt=fst[r],fst[r]=cnt;
}
//前式链向星的插入和储存
void Dijkstra(int k1)
{
    memset(dis,0,sizeof(vis));//由于求的是最长路,所以将路径长度赋一个较小值。
    vis[k1]=1;
    dis[k1]=1.0;
    for(int i=1;i<m;++i)
    {
        for(int j=fst[k1];j;j=arr[j].nxt)
        {
            int tmp=arr[j].u;
            if(dis[k1]*arr[j].v>dis[tmp])//记得符号是大于
            {
                dis[tmp]=dis[k1]*arr[j].v;
            }
        }
        double mid=0;
        for(int j=1;j<=m;++j)
        {
            if(vis[j]==0&&dis[j]>mid)//套模版,但是符号是大于
            mid=dis[j],k1=j;
        }
        vis[k1]=1;
        if(k1==k2)//如果找到b了就可以结束循环了
        {
            return;
        }
    }
}
int main()
{
    cin>>m>>n;
    for(int i=1;i<=n;++i)
    {
        int x,y,z;
        cin>>x>>y>>z;
        adds(x,y,z);
        adds(y,x,z);
        //邻接表加边
    }
    cin>>k1>>k2;
    Dijkstra(k1);//调用Dijkstra
    printf("%.8lf\n",100/dis[k2]);//输出记得保留8位小数
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值