坑题!!!!!
大下午yyf给我发了这么一道题,初看还没有思路。(第一次这么认真的写图论
blog)
题面:
在n个人中,某些人的银行账号之间可以互相转账。这些人之间转账的手
续费各不相同。给定这些人之间转账时需要从转账金额里扣除百分之几的手续
费,请问A最少需要多少钱使得转账后B收到100元。
初看很懵逼
但是仔细分析+算法标签可以发现
这个题是有关于最短路的题
为什么说?
因为我们可以建个图,人是点而手续费是边,手续费是边权。这个题初步建模
就完成了。
但是,这个题还是写不出来。
考虑完了最短路,应该选择算法:
floyd dijkstra spfa
floyd显然不行 本题可以写堆优化的dijkstra或者spfa
确定算法之后发现一个非常大的坑点:松弛操作没法完成。
分析题目:
我们用dis数组表示手续费,那么dis[u]<dis[v]*edge[i].dis就是条件
为什么?
dis[u]<他俩的乘积的话,那么这个dis[u]就不是当前的最短路
要求A花最少的钱->B获得100元
说明了要求dis[B]尽量小
所以就要把这个当成松弛的条件
坑点没有完,还有个非常坑人的操作:Z是整数!
在dis数组中,这玩意显然要写成实数,所以要预处理,/100之后再进行加边。
完成了这些,题目还是没有解完。求得dis[B]是最小的汇率,我们再想100元是
怎么来的:要花的钱数*dis[B]=100
逆向思维,ans=100/dis[B]
保留小数。
C++:
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<string> #include<ctime> #include<queue> #include<set> #include<stack> #include<map> #include<algorithm> #define maxn 100001 #define INF 0x3f3f3f3f #define inf 0x3f #define maxm 1001 using namespace std; int num_edge,head[maxn],vis[maxn],n,A,B,m,x,y; queue<int> q; double dis[maxn],z,ans; struct edge{ int to,nxt; double dis; }edge[1000005]; inline void clear(){ memset(vis,0,sizeof(vis)); memset(dis,0,sizeof(dis)); } inline void addedge(int from,int to,double dis){ edge[++num_edge].nxt=head[from]; edge[num_edge].dis=1-dis; edge[num_edge].to=to; head[from]=num_edge; } void spfa(int s){ q.push(s); dis[s]=1; vis[s]=1; while(!q.empty()){ int u=q.front(); q.pop(); vis[u]=0; for(int i=head[u];i;i=edge[i].nxt){ int v=edge[i].to; if(dis[v]<dis[u]*edge[i].dis){ dis[v]=dis[u]*edge[i].dis; if(vis[v]==0){ q.push(v); vis[v]=1; } } } } } int main(){ cin>>n>>m; clear(); for(int i=1;i<=m;i++){ cin>>x>>y>>z; addedge(x,y,z/100); addedge(y,x,z/100); } cin>>A>>B; //dis[A]=1; spfa(A); ans=100/dis[B]; printf("%.8lf",ans); return 0; }