最小花费

题目描述

在 n 个人中,某些人的银行账号之间可以互相转账。这些人之间转账的手续费各不相同。给定这些人之间转账时需要从转账金额里扣除百分之几的手续费,请问 A 最少需要多少钱使得转账后 B 收到 100 元。

输入描述

第一行输入两个正整数 n,m,分别表示总人数和可以互相转账的人的对数。
以下 m 行每行输入三个正整数 x,y,z,表示标号为 x 的人和标号为 y 的人之间互相转账需要扣除z%的手续费 (z<100)。
最后一行输入两个正整数 A,B。数据保证 A 与 B 之间可以直接或间接地转账。

输出描述

输出 A 使得 B 到账 100 元最少需要的总费用。精确到小数点后 8 位。

样例输入
3 3
1 2 1
2 3 2
1 3 3
1 3
样例输出
103.07153164

首先要先理解题目,从一号转到三号有两种方法,1->2->3或者1->3,这里的z分别为1,2,3,代表1%,2%,3%,那么转账后剩下的就分别是99%,98%,97%,那么,方法一就能剩下99%乘98%等于97.02%,方法二剩下97%,方法一剩的多,就学用,那么那一百元就是转账钱数的97.02%,转账钱数就是100/97.02%约等于103.07153164( 八位小数 )。

好,现在题目理解了,开始理思路,所以这道题要求的,就是1到n路径边权的乘积最大值,最后用一百除以这个最大值,得出答案,那这道题就很好解了,在dijkstra的基础上,改优先队列的重载函数,改dis数组初始化,改更新条件,就行了

#include<bits/stdc++.h>
using namespace std;
const int N=2005;
struct node{
	int to;
	double val;
	friend bool operator <(node a,node b){
		return a.val<b.val;
	}
};
vector<node>a[N];
int n,m;
priority_queue<node>q;
double dis[N];
int vis[N];
int st,ed;
void dij(){
	for(int i=1;i<=n;i++)dis[i]=0;//因为是最大值,所以赋值为零
	dis[st]=1;
	q.push(node{st,1});
	while(!q.empty()){
		int x=q.top().to;
		q.pop();
		if(vis[x]==1)continue;
		vis[x]=1;
		for(int i=0;i<a[x].size();i++){
			int v=a[x][i].to;
			double w=a[x][i].val;
			if(dis[v]<dis[x]*w){//注意是小于
				dis[v]=dis[x]*w;
				if(vis[v]==0){
					q.push(node{v,dis[v]});
				}
			}
		}
	}
}
signed main(){
	scanf("%d%d",&n,&m);
	int x,y,z;
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&x,&y,&z);
		double xx=1.0*(100-z)/100;
		a[x].push_back(node{y,xx});
		a[y].push_back(node{x,xx});
	}
	scanf("%d%d",&st,&ed);
	dij();
	printf("%.8lf",100.0/dis[ed]);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值