[C++一本通-圖論算法] 例4-4 最小花費

題目描述

在n我的中,某些人的銀行帳號之間能夠互相轉帳。這些人之間轉帳的手續費各不相同。給定這些人之間轉帳時須要從轉帳金額里扣除百分之幾的手續費,請問A最少須要多少錢使得轉帳後B收到100元。ios

輸入輸出格式

輸入格式:

第一行輸入兩個正整數n,m,分別表示總人數和能夠互相轉帳的人的對數。
如下m行每行輸入三個正整數x,y,z,表示標號爲x的人和標號爲y的人之間互相轉帳須要扣除z%的手續費 (z<100)。
最後一行輸入兩個正整數A,B。數據保證A與B之間能夠直接或間接地轉帳。spa

輸出格式:

輸出A使得B到帳100元最少須要的總費用。精確到小數點後8位。code

輸入輸出樣例

輸入樣例#1:

3 3
1 2 1
2 3 2
1 3 3
1 3ci

輸出樣例#1:

103.07153164io

數據範圍說明

1<=n<=2000class

解題思路

這一題數據較大,因此用Dijkstra,\(O(n^2)\) 實現。因爲從一個帳戶轉錢到另一個帳戶的手續費不一樣,因此咱們視它們爲邊的權值。先求出去掉手續費後所遺留下的錢,並在尋找路徑時儘可能去找能留下更多錢的路徑(注意在起始點時要給它賦值爲1),並將權值相乘,最後拿100除以權值相乘獲得的最大值,輸出答案。stream

實現代碼

#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]);
    return 0;
}
相關文章
相關標籤/搜索