Dijkstra

                Dijkstra一种求最短路径方法,基本思想是找一个距离最短的,把这个点距离给确定。再以这个点为中转站遍历一遍它能到的点(设成a),看看a到起点距离是否因为中转站变得更短,如果更短更新a到起点距离;不断重复这个过程。如图

                在这里插入图片描述

 1.先找一个起点A

 2设置两个集合 T,W.。其中T 为确定距离的 ,W为不确定最短路径的 。

3初始化A-A 的距离是0,到B 的距离是4,到D的距离是2,到CE 距离是无限;把能达到的点放入W中;   

4从W 中找距离最短的;此时是A-D距离是2,把A-D距离确定为二放入T数组中。

5更新U内点的距离    if ( ‘D 到 B,C,E 的距离’ + ‘AD 距离’ < ‘A 到 B,C,E 的距离’ ) 则更新U。

6重复直到结束。

例题1

1376:信使(msner)


时间限制: 1000 ms         内存限制: 65536 KB
提交数: 10624     通过数: 5337

【题目描述】

战争时期,前线有n个哨所,每个哨所可能会与其他若干个哨所之间有通信联系。信使负责在哨所之间传递信息,当然,这是要花费一定时间的(以天为单位)。指挥部设在第一个哨所。当指挥部下达一个命令后,指挥部就派出若干个信使向与指挥部相连的哨所送信。当一个哨所接到信后,这个哨所内的信使们也以同样的方式向其他哨所送信。直至所有n个哨所全部接到命令后,送信才算成功。因为准备充足,每个哨所内都安排了足够的信使(如果一个哨所与其他k个哨所有通信联系的话,这个哨所内至少会配备k个信使)。

现在总指挥请你编一个程序,计算出完成整个送信过程最短需要多少时间。

【输入】

第1行有两个整数n和m,中间用1个空格隔开,分别表示有n个哨所和m条通信线路,且1≤n≤100。

第2至m+1行:每行三个整数i、j、k,中间用1个空格隔开,表示第i个和第j个哨所之间存在通信线路,且这条线路要花费k天。

【输出】

一个整数,表示完成整个送信过程的最短时间。如果不是所有的哨所都能收到信,就输出-1。

【输入样例】

4 4
1 2 4
2 3 7
2 4 1
3 4 6

【输出样例】

11

代码

//求一遍从指挥部到任意一个哨所的最短路
//最后求出指挥部到哨所的最远距离 
#include<bits/stdc++.h>
using namespace std;
const int mxv=0x3f3f3f3f;
int n,m;
int x,y,z;
int k;
int p[109][109],//点到点距离 
dis[109];//每个点到起点距离 
bool flag[109];//判断距离是否确定true确定false不确定; 
int main(){
    memset(dis,0x3f,sizeof(dis));//初始化每个点距离无限 
    memset(p,0x3f,sizeof(p));//始化点到点距离无限 
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        cin>>x>>y>>z;
        p[x][y]=p[y][x]=z;//x到y与y到x距离都是z 
    }
    for(int i=1;i<=n;i++){
        dis[i]=p[1][i];//起点是1把1能连接到的点初始化 
    }
    dis[1]=0;//1到1距离是0; 
    flag[1]=true;//距离是0确定了,标记true 
    for(int i=1;i<=n-1;i++){
        int minn=mxv;
        for(int j=1;j<=n;j++){
            if(flag[j]==false&&dis[j]<minn){
                k=j;
                minn=dis[j];//如果flag[j]==false证明没有确定位置, dis[j]<minn证明能走到,为w集合,
            // 此时在w集合中找一个距离最短的 
            }
        }
        flag[k]=true;//把距离最短的标记true放入t集合中 
        for(int j=1;j<=n;j++){
            if(flag[j]==false&&dis[j]>dis[k]+p[k][j]){
                dis[j]=dis[k]+p[k][j];//执行第5步 
            }
        }
    }
    int ans=0;
    for(int i=2;i<=n;i++){
        ans=max(ans,dis[i]);
    }
    cout<<ans<<endl;
}

例二

1344:【例4-4】最小花费


时间限制: 1000 ms         内存限制: 65536 KB
提交数: 9379     通过数: 4012

【题目描述】

在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<=n<=2000

代码

//和上一题几乎一样
//求出剩余的最大百分比,用100除以它 
#include<bits/stdc++.h>
using namespace std;
int n,m,e,d;
int x,y,k;
int z;
double p[2009][2009],dis[2009];
bool flag[2009];
int main(){
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        cin>>x>>y;
        cin>>z;
        p[x][y]=p[y][x]=0.01*(100-z);
    }
    cin>>e>>d;
    for(int i=1;i<=n;i++){
        dis[i]=p[e][i];
    }
    dis[e]=1.0;flag[e]=true;
    for(int i=1;i<=n;i++){
        double minn=0;
        for(int j=1;j<=n;j++){
            if(flag[j]==false&&dis[j]>minn){
                k=j;
                minn=dis[j];
            }
        }
        flag[k]=true;
        for(int j=1;j<=n;j++){
            if(flag[j]==false&&dis[j]<dis[k]*p[k][j]){
                dis[j]=dis[k]*p[k][j];
            }
        }
        k=-1;
    }
     printf("%.8lf", 100*1.0/dis[d]);
}

 

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值