图论--最短路径问题--Dijkstra算法和Floyd算法

最短路径之

      (一)简单了解:

用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法能得出最短路径的最优解,但由于它遍历计算的节点很多,所以效率低。

最短路径问题是
图论研究中的一个经典算法问题, 旨在寻找图(由结点和路径组成的)中两结点之间的最短 路径。
算法具体的形式包括:
确定起点的最短路径问题 – 即已知起始结点,求最短路径的问题。 确定终点的最短路径问题 – 与确定起点的问题相反,该问题是已知终结结点,求最短路径的问题。在无向图中该 问题与确定起点的问题完全等同,在
有向图中该问题等同于把所有路径方向反转的确定起点的问题。 确定起点终点的最短路径问题 – 即已知起点和终点,求两结点之间的最短路径。 全局最短路径问题 – 求图中所有的最短路径。
所谓单源最短路径问题是指:已知图G=(V,E),我们希望找出从某给定的源结点S∈V到V中的每个结点的最短
路径。
首先,我们可以发现有这样一个事实:如果P是G中从vs到vj的最短路,vi是P中的一个点,那么,从vs沿P
到vi的路是从vs
到vi的最短路。




(二)解决方法:
Dijkstra算法
SPFA算法\Bellman-Ford算法http://blog.csdn.net/pfl_327/article/details/77102540
Floyd算法\Floyd-Warshall算法
Dijkstra算法和Floyd算法在下面讲:
(三)Dijkstra算法:
(①)了解:
迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法
是从一个顶
点到
其余各顶点的
最短路径
算法,解决的是有向图中最短路径问题。迪杰斯特拉算法主要特点是以起始点为中心向
外层
层扩展,直到扩展到终点为止。

Dijkstra算法是典型的算法Dijkstra算法是很有代表性的算法。Dijkstra一般的表述通常有两种方式,一种用永久和
临时标号方式,一种是用OPEN, CLOSE表的方式,这里均采用永久和临时标号的方式。注意该算法要求图中不存
在负权边。

(②)原理:

《图论--最短路径问题--Dijkstra算法和Floyd算法》

如上图,是求a到b的最短路径,这里并不限定b节点,修改为到任意节点的路径,问题是完全一样的。


首先需要记录每个点到原点的距离,这个距离会在每一轮遍历的过程中刷新。每一个节点到原点的最短路径是其上一

个节点(前驱节点)到原点的最短路径加上前驱节点到该节点的距离。以这个原则,经过N轮计算就能得到每一个

节点的最短距离。


第一轮,可以计算出,2、3、4、5、6到原点1的距离分别为:[7, 9, -1, -1, 14]。-1表示无穷大。取其中最小的,

为7,即可以确定1的最短路径为0,2为下一轮的前驱节点。同时确定2节点的最短路径为7,路线:1->2。


第二轮,取2节点为前驱节点,按照前驱节点的最短距离加上该节点与前驱节点的距离计算新的最短距离,可以得

到3,4,5,6节点到原点的距离为:[17, 22, -1, -1],此时需要将这一轮得到的结果与上一轮的比较,

3节点:17 > 9,最短路径仍然为9;4节点:22 < 无穷大,刷新4节点的最短路径为22;5节点:不变,仍然为无穷

大;6节点:14 < 无穷大,取14,不变。则可以得到本轮的最短距离为:[9, 22, -1, 14],取最短路径最小的节点,

为3,作为下一轮的前驱节点。同时确定3节点的最短路径为9,路线:1->3。


第三轮,同上,以3为前驱节点,得到4,5,6的计算距离为:[20, -1, 11],按照取最短路径的原则,与上一轮的进

行比较,刷新为:[20, –1, 11],选定6为下一轮的前驱节点。同时取定6的最短路径为11,路线:1->3->6。


第四轮,同上,以6为前驱节点,得到4和5的计算距离为[20, 20],与上一轮进行比较,刷新后为[20, 20],二者相等

只剩下两个节点,并且二者想等,剩下的计算已经不需要了。则两个节点的最短路径都为20。整个计算结束。4的

最短路径为20,路线:1->3->4。5的最短路径为20,路线:1->3->6->5。


如果二者不相等,则还需要进行第五轮,先确定二者中的一个的最短路径和路线,再取定剩下的。直到整个5次循

环都完成。

(③)dijkstra算法的流程图如下所示:

《图论--最短路径问题--Dijkstra算法和Floyd算法》

(④)Dijkstra算法的执行步骤:

1.先初始化D[i]=v与i之间的距离(若两点不相连则为INIFY),mark[i]=0,p[i]=0,并将起始节点v的mark[v]=0;

2.遍历剩余的节点,找出剩余节点与v之间的距离(初始状态下除去相连的节点间有距离外其余所有节点间距离为INIFY),不相连的节点依然设为INIFY不变。找出其中与v距离最小的那个点k,mark[k]=1;

3.遍历所有节点,对其中mark[i]==0的点与k点的距离+2中的那个最小距离与D[i]比较,若小于D[i]则更新D[i],并将p[i]标记为k(k为该节点的前驱)。

4.遍历完后得到的D[i]就是v到各个节点的最短距离.

(⑤).Dijkstra算法的实现:
int dijkstra(int n)
{
     //初始化v[0]到v[i]的距离
     for(int i=1;i<=n;i++)
         dis[i] = w[0][i];                                       
     vis[0]=1;//标记v[0]点
     for(int i = 1; i <= n; i++)
     {
         //查找最近点
        int min = INF,k = 0;
        for(int j = 0; j <= n; j++)
            if(!vis[w] && dis[j] < min)
                min = dis[w],k = j;
        vis[k] = 1;//标记查找到的最近点
         //判断是直接v[0]连接v[j]短,还是经过v[k]连接v[j]更短
        for(int j = 1; j <= n; j++)
           if(!vis[j] && min+w[k][j] < dis[j])
               d[j] = min+w[k][j];
    }
    return dis[j];
}

(⑥).例题:
①:大学经典教材<<数据结构>>(C语言版 严蔚敏 吴为民 编著) 中该算法的实现
测试数据 教科书 P189 G6 的邻接矩阵 其中 数字 1000000 代表无穷大
6
1000000 1000000 10 100000 30 100
1000000 1000000 5 1000000 1000000 1000000
1000000 1000000 1000000 50 1000000 1000000
1000000 1000000 1000000 1000000 1000000 10
1000000 1000000 1000000 20 1000000 60
1000000 1000000 1000000 1000000 1000000 1000000
结果:
D[0]   D[1]   D[2]   D[3]   D[4]   D[5]
 0   1000000   10     50     30     60

#include <iostream>
#include <cstdio>
#define MAX 1000000
using namespace std;
int arcs[10][10];//邻接矩阵
int D[10];//保存最短路径长度
int p[10][10];//路径
int final[10];//若final[i] = 1则说明 顶点vi已在集合S中
int n = 0;//顶点个数
int v0 = 0;//源点
int v,w;
void ShortestPath_DIJ()
{
     for (v = 0; v < n; v++) //循环 初始化
     {
          final[v] = 0; D[v] = arcs[v0][v];
          for (w = 0; w < n; w++) 
p[v][w] = 0;//设空路径
          if (D[v] < MAX) {p[v][v0] = 1; p[v][v] = 1;}
     }
     D[v0] = 0; final[v0]=0; //初始化 v0顶点属于集合S
     //开始主循环 每次求得v0到某个顶点v的最短路径 并加v到集合S中
     for (int i = 1; i < n; i++)
     {
          int min = MAX;
          for (w = 0; w < n; w++)
          {
               //我认为的核心过程–选点
               if (!final[w]) //如果w顶点在V-S中
               {
                    //这个过程最终选出的点 应该是选出当前V-S中与S有关联边
                    //且权值最小的顶点 书上描述为 当前离V0最近的点
                    if (D[w] < min) {v = w; min = D[w];}
               }
          }
          final[v] = 1; //选出该点后加入到合集S中
          for (w = 0; w < n; w++)//更新当前最短路径和距离
          {
               /*在此循环中 v为当前刚选入集合S中的点
               则以点V为中间点 考察 d0v+dvw 是否小于 D[w] 如果小于 则更新
               比如加进点 3 则若要考察 D[5] 是否要更新 就 判断 d(v0-v3) + d(v3-v5) 的和是否小于D[5]
               */
               if (!final[w] && (min+arcs[v][w]<D[w]))
               {
                    D[w] = min + arcs[v][w];
                   // p[w] = p[v];
                    p[w][w] = 1; //p[w] = p[v] + [w]
               }
          }
     }
}
 
 
int main()
{
    cin >> n;
    for (int i = 0; i < n; i++)
    {
         for (int j = 0; j < n; j++)
         {
              cin >> arcs[i][j];
         }
    }
    ShortestPath_DIJ();
    for (int i = 0; i < n; i++) printf(“D[%d] = %d\n”,i,D[i]);
    return 0;
}



②:Dijkstra算法—HDU 2544 水题(模板)http://acm.hdu.edu.cn/showproblem.php?pid=2544

题目大意:

搬东西很累,想省力,给你几个点和点之间的距离;标准题型;

输入:包括多组数据。每组数据第一行是两个整数N、M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。
输入保证至少存在1条商店到赛场的路线。

测试数据:
Sample Input

2 1 1 2 3 3 3 1 2 5 2 3 5 3 1 2 0 0
 


Sample Output

3 2
#include<cstdio>
#include <iostream>
#include<cstring>
using namespace std;
#define INF 0xfffffff
int maps[110][110],dis[110],visit[110];//maps[1][2]=10为点1到点2的值为10;visit[1]=1 为1这个点已经处理
int n,m;//n为多少个路口也就是多少个点,m为多少条路也就是多少个相互连接的点
int dijstra()
{
    memset(visit,0,sizeof(visit));//初始化visit的所有的值
    for (int i=1;i<=n;i++)
    {
        dis[i]=maps[1][i];//将1点到其他所有点的值赋给dis[i];
    }
    visit[1]=1;//标记1点已经处理
    dis[1]=0;//到自己的距离为0
    for (int i=1;i<=n;i++)
    {
        int pos;//记录j值;
        int mins=INF;//记录最小值
        for (int j=1;j<=n;j++)
        {
            if (!visit[j]&&mins>dis[j])//j点未被处理,且j点到1点的值最小
            {
                pos=j;//记住j这个点
                mins=dis[j];//更新最小值
            }
        }
        visit[pos]=1;//已经处理pos这个点;
        for (int j=1;j<=n;j++)
        {
            if (!visit[j]&&dis[j]>dis[pos]+maps[pos][j])//循环不断找出结点;
            {
                dis[j]=dis[pos]+maps[pos][j];
            }
        }
    }
    return dis[n];//终点在n这个地方;
}
int main()
{
    int i,j;
    while(~scanf(“%d%d”,&n,&m),n||m)
    {
        for(i=1;i<=n;++i)
        {
            for(j=1;j<=n;++j)
            {
                maps[i][j]=INF;
            }
        }
        int a,b,c;//a,b都为两个相互连接的点,c为连接的距离
        for(i=1;i<=m;++i)
        {
            scanf(“%d%d%d”,&a,&b,&c);
            if(c<maps[a][b])
            maps[a][b]=maps[b][a]=c;
        }

        int counts=dijstra();
        printf(“%d\n”,counts);
    }
    return 0;
}

③HDU – 2112 (徐总坐公交车)
Input
输入数据有多组,每组的第一行是公交车的总数N(0<=N<=10000); 
第二行有徐总的所在地start,他的目的地end; 
接着有n行,每行有站名s,站名e,以及从s到e的时间整数t(0<t<100)(每个地名是一个长度不超过30的字符串)。 
note:一组数据中地名数不会超过150个。 
如果N==-1,表示输入结束。 

Output
如果徐总能到达目的地,输出最短的时间;否则,输出“-1”。 

Sample Input

6
xiasha westlake
xiasha station 60
xiasha ShoppingCenterofHangZhou 30
station westlake 20
ShoppingCenterofHangZhou supermarket 10
xiasha supermarket 50
supermarket westlake 10
-1

Sample Output

50

仔细看代码可能会理解(Dijkstra算法):
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define INF 0x3ffffff
#define MAXs 170
using namespace std;
int dis[MAXs],visit[MAXs],maps[MAXs][MAXs];
char s[35],e[35],place[MAXs][35];
int counts;
void Dijkstra(int start,int endd)
{
    //int pos=start;
    memset(visit,0,sizeof(visit));
    for(int i=1;i<=counts;i++)
        dis[i]=maps[start][i];
    visit[start]=1;
    dis[start]=0;
    for(int i=1;i<=counts;i++)
    {
        int mins=INF;
        int pos;
        for(int j=1;j<=counts;j++)
            if(!visit[j]&&mins>dis[j])
            {
                mins=dis[j];
                pos=j;
            }
        visit[pos]=1;
        for(int j=1;j<=counts;j++)
            if(!visit[j]&&dis[j]>dis[pos]+maps[pos][j])
                dis[j]=dis[pos]+maps[pos][j];
    }
    if(dis[endd]==INF)
        printf(“-1\n”);
    else
        printf(“%d\n”,dis[endd]);
}
int main()
{
    int N;
    int a,b,sign,leng;
    while(~scanf(“%d”,&N)&&N!=-1)
    {
        for(int i=1;i<MAXs;i++)//初始化maps[][]
            for(int j=1;j<MAXs;j++)
            {
                if(i==j)
                    maps[i][j]=0;
                else
                    maps[i][j]=INF;
            }
       scanf(“%s%s”,place[1],place[2]);//起始点
       counts=2;
       while(N–)
       {
           int leng;//两点的距离
           scanf(“%s%s%d”,s,e,&leng);//输入并提示两点及距离
            sign=0;//相当于标记变量
            for(int i=1;i<=counts;i++)
                if(strcmp(s,place[i])==0)//查找是否记录到数组中
                {
                    sign=1;
                    a=i;//记录匹配到的位置;
                    break;
                }
            if(!sign)
            {
                counts++;
                strcpy(place[counts],s);
                a=counts;
            //若没有记录入数组,则加入数组,其字符串地名对应的编号即为数组的下标,当前的counts值
            }
            //重复操作对比站点e
            sign=0;//需要更新sign的值
            for(int i=1;i<=counts;i++)
                if(strcmp(e,place[i])==0)
                {
                    sign=1;
                    b=i;
                    break;
                }
            if(!sign)
            {
                counts++;
                strcpy(place[counts],e);
                b=counts;
            }
            if(maps[a][b]>leng)
                maps[a][b]=maps[b][a]=leng;
       }
       if(strcmp(place[1],place[2])==0)
            printf(“0\n”);
       else
            Dijkstra(1,2);
    }
    return 0;
}

解题思路:这个题是要求输入起点与终点的,难点是对字符串的处理。开始会对maps[][]进行初始化,每行输入的站点与之间的距离要全部放入到maps这个数组中,然后用Dijkstra算法进行处理。



接下来是SPFA算法的代码:
#include <iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<map>
#define N 170
#define INF 0x3ffffff
using namespace std;

int counts,n,maps[N][N],dis[N],visit[N];//visit数组为标记数组,dis未记录距离的数组
//map为存储各个点且值为两点的距离,counts为记录有多少种情况,n为输入值

int spfa(int start,int endd)
{
    if(start==endd)
        return 0;//处理起点与终点相同的时候
        
    memset(visit,0,sizeof(visit));
    for(int i=1;i<=counts;i++)//必须初始化
       dis[i]=INF;//而且只能这样初始化

    dis[start]=0;
    visit[start]=1;//也是必要的初始化

    queue<int> Q;//队列
    Q.push(start);
    while(!Q.empty())
    {
        int x=Q.front();
        Q.pop();
        visit[x]=0;//这些都是队列的一般操作

        for(int i=1;i<=counts;i++)//下面这些是SPFA算法求最短路的一些基本操作
        {
            if(dis[i]>dis[x]+maps[x][i])
            {
                dis[i]=dis[x]+maps[x][i];
                if(!visit[i])
                {
                    visit[i]=1;
                    Q.push(i);
                }
            }
        }
    }
    if(dis[endd]==INF)
        return -1;
    else
        return dis[endd];
}

int main()
{
    while(~scanf(“%d”,&n)&&n!=-1)
    {
        for(int i=1;i<N;i++)
            for(int j=1;j<N;j++)
                maps[i][j]=INF;
        map<string,int>mp;//定义一个map类型的变量
        mp.clear(); //清除所有数据;
        char s[110],e[110];
        scanf(“%s%s”,s,e);
        counts=1;
        mp[s]=counts++;
        if(mp[e]==0)
            mp[e]=counts++;
        while(n–)
        {
            int leng;
            char ss[110],ee[110];
            scanf(“%s%s%d”,ss,ee,&leng);
            if(mp[ss]==0)
                mp[ss]=counts++;
            if(mp[ee]==0)           
                mp[ee]=counts++;    
            if(maps[mp[ss]][mp[ee]]>leng)
                maps[mp[ss]][mp[ee]]=maps[mp[ee]][mp[ss]]=leng;
        }
        printf(“%d\n”,spfa(mp[s],mp[e]));
    }
}

理解:
相比于上边Dijkstra算法,用到map()函数确实对于字符串的处理有了很方便的地方,接下来的SPFA算法基本上就是在套用模板,但是还是要注意一些细节,一些变量的初始化。
还有就是counts++与++counts问题:
记住是先传递还是后传递,例如a=counts++是先把值counts原先的值赋给a,接着在counts加一,
a=++counts是先counts加一,在把counts赋给a;
例:
counts=1;
a=counts++;
b=counts;这样:a=1,b=2;
若a=++counts;这样a=2,b=2;不要太计较其他的就可以了;


还有就是即将要讲的Floyd算法代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define INF 0x3fffff
#define MAXS 170
using namespace std;
int maps[MAXS][MAXS];
int n;

void Floyd(int n)
{
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(maps[i][k]!=INF&&maps[k][j]!=INF)
                    maps[i][j]=min(maps[i][k]+maps[k][j],maps[i][j]);
    //Floyd算法模板
        if(maps[1][2]==INF)
             printf(“-1\n”);
        else
            printf(“%d\n”,maps[1][2]);
}
int main()
{
    while(~scanf(“%d”,&n)&&n!=-1)
    {
        for(int i=1;i<MAXS;i++)
            for(int j=1;j<MAXS;j++)
            {
                maps[i][j]=INF;
            }
        map<string,int>mmap;//使用map()函数
        mmap.clear();
        
        int counts=3;
        char s[35],e[35];
        scanf(“%s%s”,s,e);
        mmap[s]=1;
        mmap[e]=2;
        while(n–)
        {
            int leng;
            char ss[35],ee[35];
            scanf(“%s%s%d”,ss,ee,&leng);
            if(!mmap[ss])
                mmap[ss]=counts++;
            if(!mmap[ee])
                mmap[ee]=counts++;
            if(maps[mmap[ss]][mmap[ee]]>leng)
                maps[mmap[ss]][mmap[ee]]=maps[mmap[ee]][mmap[ss]]=leng;
        }//输入数据处理
        if(strcmp(s,e)==0)
            printf(“0\n”);//起始点重合的情况
        else
            Floyd(counts-1);
    }
    return 0;
}

学完Floyd算法看到那简短的代码,就直到压缩的全是精华了,所以记住模板差不多就可以:
for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(maps[i][k]!=INF&&maps[k][j]!=INF)
                    maps[i][j]=min(maps[i][k]+maps[k][j],maps[i][j]);
    //Floyd算法模板
其他的地方和上边的算法差不多,。多多理解。

(四)Floyd算法
①:理解
Floyd算法又称为插点法,是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似。

算法思想原理:

     Floyd算法是一个经典的动态规划算法,稠密图效果最佳,边权可正可负。此算法简单有效,由于三重循环结构紧凑,对于稠密图,效率要高于执行|V|次Dijkstra算法,也要高于执行|V|次SPFA算法用通俗的语言来描述的话,首先我们的目标是寻找从点i到点j的最短路径。从动态规划的角度看问题,我们需要为这个目标重新做一个诠释(这个诠释正是动态规划最富创造力的精华所在)

      从任意节点i到任意节点j的最短路径不外乎2种可能,1是直接从i到j,2是从i经过若干个节点k到j。所以,我们假设Dis(i,j)为节点u到节点v的最短路径的距离,对于每一个节点k,我们检查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,如果成立,证明从i到k再到j的路径比i直接到j的路径短,我们便设置Dis(i,j) = Dis(i,k) + Dis(k,j),这样一来,当我们遍历完所有节点k,Dis(i,j)中记录的便是i到j的最短路径的距离。



算法描述:

a.从任意一条单边路径开始。所有两点之间的距离是边的权,如果两点之间没有边相连,则权为无穷大。   

b.对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比己知的路径更短。如果是更新它。

②:基本代码

很简单吧,代码看起来可能像下面这样: 

[cpp] view plain copy

  1. for ( int i = 0; i < 节点个数; ++i )  
  2. {  
  3.     for ( int j = 0; j < 节点个数; ++j )  
  4.     {  
  5.         for ( int k = 0; k < 节点个数; ++k )  
  6.         {  
  7.             if ( Dis[i][k] + Dis[k][j] < Dis[i][j] )  
  8.             {  
  9.                 // 找到更短路径  
  10.                 Dis[i][j] = Dis[i][k] + Dis[k][j];  
  11.             }  
  12.         }  
  13.     }  
  14. }  

但是这里我们要注意循环的嵌套顺序,如果把检查所有节点X放在最内层,那么结果将是不正确的,为什么呢?因为这样便过早的把i到j的最短路径确定下来了,而当后面存在更短的路径时,已经不再会更新了。

让我们来看一个例子,看下图:

《图论--最短路径问题--Dijkstra算法和Floyd算法》

图中红色的数字代表边的权重。如果我们在最内层检查所有节点X,那么对于A->B,我们只能发现一条路径,就是A->B,路径距离为9。而这显然是不正确的,真实的最短路径是A->D->C->B,路径距离为6。造成错误的原因就是我们把检查所有节点X放在最内层,造成过早的把A到B的最短路径确定下来了,当确定A->B的最短路径时Dis(AC)尚未被计算。所以,我们需要改写循环顺序,如下:

[cpp] view plain copy

  1. for ( int k = 0; k < 节点个数; ++k )  
  2. {  
  3.     for ( int i = 0; i < 节点个数; ++i )  
  4.     {  
  5.         for ( int j = 0; j < 节点个数; ++j )  
  6.         {  
  7.             if ( Dis[i][k] + Dis[k][j] < Dis[i][j] )  
  8.             {  
  9.                 // 找到更短路径  
  10.                 Dis[i][j] = Dis[i][k] + Dis[k][j];  
  11.             }  
  12.         }  
  13.     }  
  14. }  

毕竟这个算法比较简单加上上边也有有关例题,所以再找一个简单的例题!!

poj 3615 Cow Hurdles

题意:

        给你一个有向图,然后对于特定的点A与B,要你求出A到B之间所有可行路径的单段路距离最大值的最小值.(有点绕)

分析:

        剥除floyd的外壳,本题d[i][j]表示的是从i到j的所有路径中单段路距离最大值的最小值。所以其实本题还是依据动态规划的思想来做的,

 当不同类d[i][k]和d[k][j]合并的时候,取得是max(最大值,因为我们要求i到j这段路内的最大值)。然后当同类路径值(即两个d[i][j]可行值)选优时,取得是最小值(因为我们要求所有i到j路径目的值中的最小值)。

代码:

#include<cstdio>  
#include<algorithm>  
#define INF 1e9  
using namespace std;  
const int maxn = 300+10;  
int n,m,t;  
int d[maxn][maxn];  
void floyd()  
{  
    for(int k=1;k<=n;k++)  
    for(int i=1;i<=n;i++)  
    for(int j=1;j<=n;j++)  
        if(d[i][k]<INF &&d[k][j]<INF)  
            d[i][j]=min(d[i][j],max(d[i][k],d[k][j]));  
}  
int main()  
{  
    while(scanf(“%d%d%d”,&n,&m,&t)==3)  
    {  
        for(int i=1;i<=n;i++)  
        for(int j=1;j<=n;j++)  
            d[i][j]= i==j?0:INF;  
        for(int i=1;i<=m;i++)  
        {  
            int u,v,height;  
            scanf(“%d%d%d”,&u,&v,&height);  
            d[u][v]=height;  
        }  
        floyd();  
        while(t–)  
        {  
            int u,v;  
            scanf(“%d%d”,&u,&v);  
            printf(“%d\n”,d[u][v]==INF?-1:d[u][v]);  
        }  
    }  
    return 0;  


(五)知识点:
具体map函数讲解:http://blog.csdn.net/pfl_327/article/details/77188385

 
map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道。这里说下map内部数据的组织,map内部自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的,后边我们会见识到有序的好处。
map的基本操作函数
C++ Maps是一种关联式容器,包含“关键字/值”对
begin() 返回指向map头部的迭代器
clear() 删除所有元素
count() 返回指定元素出现的次数
empty() 如果map为空则返回true
end() 返回指向map末尾的迭代器
equal_range() 返回特殊条目的迭代器对
erase() 删除一个元素
find() 查找一个元素
get_allocator() 返回map的配置器
insert() 插入元素
key_comp() 返回比较元素key的函数
lower_bound() 返回键值>=给定元素的第一个位置
max_size() 返回可以容纳的最大元素个数
rbegin() 返回一个指向map尾部的逆向迭代器
rend() 返回一个指向map头部的逆向迭代器
size() 返回map中元素的个数
swap() 交换两个map
upper_bound() 返回键值>给定元素的第一个位置
value_comp() 返回比较元素value的函数

    原文作者:Dijkstra算法
    原文地址: https://blog.csdn.net/pfl_327/article/details/77161374
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞