最短路径-Floyed和Dijkstra
Floyed
样题一:P1364 医院设置
题目描述:
设有一棵二叉树,如图:

其中,圈中的数字表示结点中居民的人口。圈边上数字表示结点编号,现在要求在某个结点上建立一个医院,使所有居民所走的路程之和为最小,同时约定,相邻接点之间的距离为 11。如上图中,若医院建在1 处,则距离和 =4+12+2\times20+2\times40=136=4+12+2×20+2×40=136;若医院建在 33 处,则距离和 =4\times2+13+20+40=81=4×2+13+20+40=81。
输入格式:
第一行一个整数 nn,表示树的结点数。
接下来的 nn 行每行描述了一个结点的状况,包含三个整数 w, u, vw,u,v,其中 ww 为居民人口数,uu 为左链接(为 00 表示无链接),vv 为右链接(为 00 表示无链接)。
输出格式:
一个整数,表示最小距离和。
输入输出样例:
 | 5						 13 2 3 4 0 0 12 4 5 20 0 0 40 0 0
 
  | 
输出:
程序源代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
   | #include <bits/stdc++.h> using namespace std; int tree[1000][1000];    int w[1000],l,r;   int mindis;        int main() {     int n;     cin>>n;     for(int i=1;i<=n;i++)     {         for(int j=1;j<=n;j++)         {             tree[i][j]=0X3FFFFFFF;             }     }     for (int i = 1; i <=n ; ++i) {         tree[i][i]=0;             cin>>w[i]>>l>>r;           if(l>0) tree[i][l]=tree[l][i]=1;         if(r>0) tree[i][r]=tree[r][i]=1;     }     for (int k = 1; k <=n ; ++k)      {         for (int i = 1; i <=n ; ++i) {             if(i!=k)             {                 for (int j = 1; j <=n ; ++j) {                     if(i!=j&&j!=k&&tree[i][k]+tree[k][j]<tree[i][j])                     {                         tree[i][j]=tree[i][k]+tree[k][j];                     }                 }             }         }     }     mindis=INT_MAX;     for(int i=1;i<=n;i++)      {         int sum =0;         for(int j=1;j<=n;j++)         {             sum+=tree[i][j]*w[j];         }         if(sum<mindis) mindis=sum;     }     cout<<mindis<<endl;     return 0; }
 
  | 
Dijkstra
样题二:
题目描述:

输入n和m,代表n个节点,m条边,然后是m行输入,每行有x,y,z,代表x到y的路距离为z。
问题:从1出发到各点的最短路径
测试样例:
 | 7 12 1 2 20 1 3 50 1 4 30 2 3 25 2 6 70 3 4 40 3 6 50 3 5 25 4 5 55 5 6 10 5 7 70 6 7 50 5
 
  | 
输出:
程序源代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
   | #include <bits/stdc++.h> using namespace std; const int maxn = 100; int mapdis[maxn][maxn];   int dis[maxn];   int path[maxn];   int vis[maxn];  int n,m; void Dijkstra(int s) {          memset(dis,0x3f,sizeof(dis));     memset(path,-1,sizeof(path));     memset(vis,0,sizeof(vis));          dis[s]=0;        while(1)     {         int k=0;          for (int i = 1; i <=n; ++i) {             if(!vis[i]&&dis[i]<dis[k])                  {                 k=i;                       		               }         }         if(!k) return;           vis[k]=1;                         for (int j = 1; j <=n ; ++j) {                                          if(dis[j]>dis[k]+mapdis[k][j])               {                 dis[j]=dis[k]+mapdis[k][j];                 path[j]=k;             }         }
      }
  } void print(int x)  {     if(x == -1) return;     print(path[x]);     cout<<x<<"->"; } int main() {     n,m;     cin>>n>>m;          memset(mapdis,0x3f,sizeof(mapdis));     for (int i = 0; i <m ; ++i) {         int x,y,z;         cin>>x>>y>>z;                  mapdis[x][y]=z;     }     Dijkstra(1);       int order;         cin>>order;     print(path[order]);       cout<<order<<endl;     cout<<dis[order];         return 0; }
 
 
  | 
样题三:L2-001 紧急救援 (25 分)
题目描述:
作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。
输入格式:
输入第一行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0 ~ (N−1);M是快速道路的条数;S是出发地的城市编号;D是目的地的城市编号。
第二行给出N个正整数,其中第i个数是第i个城市的救援队的数目,数字间以空格分隔。随后的M行中,每行给出一条快速道路的信息,分别是:城市1、城市2、快速道路的长度,中间用空格分开,数字均为整数且不超过500。输入保证救援可行且最优解唯一。
输出格式:
第一行输出最短路径的条数和能够召集的最多的救援队数量。第二行输出从S到D的路径中经过的城市编号。数字间以空格分隔,输出结尾不能有多余空格。
输入样例:
 | 4 5 0 3 20 30 40 10 0 1 1 1 3 2 0 3 3 0 2 2 2 3 2结尾无空行
 
  | 
输出样例:
最短路径条数:
如果通过 index 点能把最短路径更新,那么最短路径条数就是从起点到index的最短路径条数。

例如这张图,如果index可以更新当前的最短路径,并且s通过1和2到达index点的距离都相等,那么从s到d的最短路径条数其实就是从s到index的最短路径条数,由此可以得到第一个式子
如果通过index点的周转,距离不变(依然是最小值),这说明通过index周转使得最短路径条数又多出了一部分,只需要用之前得到的最短路径条数加上num[index]即可,由此得出第二个式子
程序源代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
   | #include <bits/stdc++.h> using namespace std; int n,m,s,d; const int maxn=505; int arr[maxn];    int dismap[maxn][maxn];     int path[maxn];     int dis[maxn];      int cost[maxn];     int vis[maxn];      int num[maxn];      void dijk(int s) {     memset(path,-1,sizeof(path));     memset(dis,0x3f,sizeof(dis));     memset(cost,0,sizeof(cost));     memset(vis,0,sizeof(vis));     memset(num,0,sizeof(num));     dis[s]=0;     cost[s]=arr[s];        num[s]=1;              while(true)     {         int k=-1;         int maxt =0x3f;         for (int i = 0; i < n; ++i) {             if(!vis[i]&&dis[i]<maxt)             {                 k=i;                 maxt=dis[i];             }         }         vis[k]=1;         if(k==-1) return;
          for (int j = 0; j < n; ++j) {
              if(!vis[j]&&dis[j]>dis[k]+dismap[k][j]){                 dis[j]=dis[k]+dismap[k][j];                 path[j]=k;                 num[j]=num[k];                    cost[j] = cost[k]+arr[j];               }             else if (!vis[j]&&dis[j]==dis[k]+dismap[k][j]){                  num[j]+=num[k];                     				                 if(cost[j]<cost[k]+arr[j])                    {                     cost[j]=cost[k]+arr[j];                     path[j]=k;
                  }             }
          }     }
  } void print(int x) {     if(x==-1) return;     print(path[x]);     cout<<x<<" "; } int main() {
      cin>>n>>m>>s>>d;     memset(arr,0,sizeof(arr));     memset(dismap,0x3f,sizeof(dismap));     for (int j = 0; j <n ; ++j) {         cin>>arr[j];     }     for (int i = 0; i <m ; ++i) {         int x,y,z;         cin>>x>>y>>z;                  dismap[x][y]=z;         dismap[y][x]=z;     }     dijk(s);     cout<<num[d]<<" "<<cost[d]<<endl;     print(path[d]);     cout<<d<<endl;     return 0; }
 
  | 
相关题目链接:
[P1364 医院设置 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)]: “ 样题一:P1364 医院设置”
题目详情 - L2-001 紧急救援 (25 分) (pintia.cn) :样题三:L2-001 紧急救援 (25 分)
L2-001 紧急救援 (25 分)&&dijkstra - 灰信网(软件开发博客聚合) (freesion.com):样题三参考资料