今天给大家讲最小花费这道题目。
思路
题目大意就是现在给定一些人之间转账的要给的手续费,让你求出
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位小数
}