洛谷P1576 最小花费x
题目背景
题目描述
在n个人中,某些人的银行账号之间可以互相转账。这些人之间转账的手续费各不相同。给定这些人之间转账时需要从转账金额里扣除百分之几的手续费,请问A最少需要多少钱使得转账后B收到100元。
输入输出格式
输入格式:第一行输入两个正整数n,m,分别表示总人数和可以互相转账的人的对数。
以下m行每行输入三个正整数x,y,z,表示标号为x的人和标号为y的人之间互相转账需要扣除z%的手续费 (z<100)。
最后一行输入两个正整数A,B。数据保证A与B之间可以直接或间接地转账。
输出格式:输出A使得B到账100元最少需要的总费用。精确到小数点后8位。
输入输出样例
输入样例#1:
3 3 1 2 1 2 3 2 1 3 3 1 3
输出样例#1:
103.07153164
说明
1<=n<=2000
思路:
用dis数组存起输入的:需要扣除z%的手续费,通过这个进行dijkstra
不过有一点不同就是:
普通的dijkstra是从dis数组里面往小里找,而这道题是从较大的里面找(因为最后输出的需要是最小的,那么剩余的百分之几一定是最大的)
坑点:
松弛操作的时候也如此(思路):寻找从当前点出发到达另一点得到的百分比比之前剩余金额的百分比要大才能进行松弛操作
上代码:
#include <iostream> #include <cstdio> using namespace std; const int M = 2002; int n,m,a,b,k; double map[M][M],minn; double dis[M]; bool vis[M]; void dijkstra(int start) { for(int i=1; i<=n; i++) dis[i]=map[start][i]; vis[start]=true; dis[start]=1;//必须进行赋值1,因为若进行更改将使用乘法(0*every==0) for(int i=1; i<n; i++) { minn=0; for(int j=1; j<=n; j++) if(!vis[j]&&dis[j]>minn) //寻找剩余金额最大的 minn=dis[j],k=j; vis[k]=true; if(k==b) break;//结束标志 for(int q=1; q<=n; q++) if(!vis[q]&&dis[q]<dis[k]*map[k][q]) dis[q]=dis[k]*map[k][q];//进行松弛 } } int main() { double z; scanf("%d%d",&n,&m); for(int i=1,x,y; i<=m; i++) { cin>>x>>y>>z; map[x][y]=map[y][x]=(100-z)/100;//表示是原金额的百分之几 } cin>>a>>b; dijkstra(a); printf("%.8lf\n",100/dis[b]); //绝对不能在dijkstra函数里面进行输出,因为有break操作,结果导致直接输出100 return 0; }