洛谷P1576||最小花费||dijkstra||双向建边!!
题目描述
在n个人中,某些人的银行账号之间可以互相转账。这些人之间转账的手续费各不相同。给定这些人之间转账时需要从转账金额里扣除百分之几的手续费,请问A最少需要多少钱使得转账后B收到100元。
数据范围
1<=n<=2000,m<=100000
思路分析
可以把每个人看成是一个点,那么题目描述的问题就是使得A->B的花费最少,即两点间的最短路问题,这里我们采用dijkstra算法。
由于m<=100000,故我们采用链式前向星进行存储图,每次找到一个距离原点最近并且没有被访问过的点后,遍历连接此点的每一条边,更新其连接节点的花费
代码(我把dijkstra分为两部分,这样虽然效率低,但是对于我来说思路更清晰些)
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<iomanip> #define N 300010 #define MAXX 1e7+10 #define MINN -1e7+10 using namespace std; struct road { int starts,ends,vals; }ro[N]; double firsts[N],NEXT[N]; int len=0; int n,m,A,B; double dis[N]; double inputnum[N][4]; void insert(int xx,int yy,int zz) { len++; ro[len].starts=xx;ro[len].ends=yy;ro[len].vals=zz; NEXT[len]=firsts[xx];firsts[xx]=len; } void init() { cin>>n>>m; for(int i=1;i<=m;i++) { int aa,bb,cc; cin>>aa>>bb>>cc; insert(aa,bb,cc); insert(bb,aa,cc); } cin>>A>>B; } bool flag[N]; inline void pre(){ for(int i=1;i<=n;i++) dis[i]=MAXX;} inline void dijkstra1(int st,double vv)//单源点dijkstra { for(int i=firsts[st];i;i=NEXT[i]) //如果出度的权值小于当前dis数组的权值,那么就更新dis数组 { if(dis[st]/(1-ro[i].vals*0.01)<dis[ro[i].ends]) { dis[ro[i].ends]=dis[st]/(1-ro[i].vals*0.01); } } } void dijkstra() { pre(); dis[A]=100; for(int i=firsts[A];i;i=NEXT[i]) { dis[ro[i].ends]=dis[A]/(1-ro[i].vals*0.01); } // for(int i=1;i<=n;i++) //cout<<i<<' '<<dis[i]<<' '; //cout<<endl; for(int j=1;j<=n;j++){ double minn=999999999;int temp; for(int i=1;i<=n;i++){ if(i==A) continue; if(flag[i]==1) continue; if(dis[i]<minn) { temp=i;minn=dis[i]; ////cout<<dis[i]<<' '<<minn<<endl; } } flag[temp]=1; dijkstra1(temp,minn); } } void debug_output() { for(int i=1;i<=len;i++) cout<<ro[i].starts<<' '<<ro[i].ends<<' '<<ro[i].vals<<' '<<NEXT[i]<<' '<<firsts[ro[i].starts]<<endl; } int main() { // freopen("a.in","r",stdin); // freopen("a.out","w",stdout); init(); //debug_output(); dijkstra(); cout<<fixed<<setprecision(8); // for(int i=1;i<=n;i++) cout<<dis[B]<<endl; return 0; }
posted on 2018-08-18 21:01 supersumax 阅读(180) 评论(0) 编辑 收藏 举报