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]);
}
|