最短路径

Dijkstra算法(单源最短路问题)(非递归)(非负边权)

数码宝贝拯救者

  在世界的另一端, 有一个美丽富饶的精灵大陆, 那里存在着六个城市, 城市中生存着许多小精灵。一开始, 这个大陆和平安详, 没有纷争, 但是有一天, 邪恶黑暗势力忽然侵袭统治了这片大陆,并把大陆中的六个城市用黑暗力量染成了黑色,精灵们感到十分恐惧。这时,光明之神派遣一只被称为“番长狮子“(名字叫“亚历山大“, 见图10-26) 的英雄带领军队前往解救("番长” 是精灵大陆中一个很厉害的称号, 只有实力非常强大的生灵才能拥有)。由千黑暗力量的影响,城市与城市之间只能通过某种特殊通道单向到达(即有向边),并且一些城市之间无法直接到达(即只能通过其他城市间接到达)。图10-26a 是一幅地图, 给出了六个城市(编号为从V 。至Vs) 和它们之间存在的有向边(边上的数字表示距离), 且每个城市都被污染成了黑色(表示该城市暂时没有被解救)。亚历山大在研究地图后决定从V 。开始对六个城市的敌人发起进攻, 且每成功攻下一个城市, 就用光明之力让城市中的黑暗消散,并把带来的部队驻扎在城市中, 以防黑暗势力攻回,自己则通过魔法重新回到V。, 带领新的部队攻打下一个城市。为了减少消耗,亚历山大希望每次从起点V。到达需要攻占的城市之间的路程尽可能短, 即从起点到达其他所有顶点都必须是最短距离。
在这里插入图片描述
  第一行输入n:城市数(城市编号为0~n-1);m:边数;s:起点
  接下来m行输入边和边权x,y,z:城市x->城市y的距离为z
  按城市编号的顺序依次输出从起点到达每个城市的最短距离
输入情况:
6 8 0
0 1 1
0 3 4
0 4 4
1 3 2
2 5 1
3 2 2
3 4 3
4 5 3
输出情况:
0 1 5 3 4 6

思路

番长不愧是番长,有着丰富战斗经验的亚历山大马上就想出了策略。而在执行策略之前,亚历山大对地图做了一个两个修改:
①将地图上所有边都抹去, 只有当攻占一个城市后才把从这个城市出去的边显现(笔者插话: 这个操作在实际编写代码时是自然成立、不需要人为控制的, 但是在这个例子中把这点单独提出来对理解Dijkstra操作的过程很有帮助)。
②在地图中的城市Vi (0<=i<=5)上记录从起点V0到达该城市Vi 所需要的最短距离。 由于在①中亚历山大把所有边都抹去了, 因此在初始状态下除了V0到达V0的距离是0之外,从V0到达其他城市的距离都是无穷大(记为inf, 见图10-26b)。为了方便叙述,在下文中某几处出现的最短距离都是指从起点V。到达城市vi 的最短距离。
下面是番长的行动策略
①由于要攻占六个城市,因此将步骤②③执行六次,每次攻占一个城市(如果是n个城市, 那么就执行n 次)。
每次都从还未攻占的城市中选择当前距离起点V0最近的城市(即地图的城市上记录的最短距离最小的未攻占城市, 记为Vk (O<=k<=5), 前往攻占。
@攻占城市W后, 开放地图上从Vk出发的所有边, 并查看以Vk为中介点的情况下,能否使从起点V。到达某些还未攻占的城市的最短距离变小。(和到达中介点所需的最短距离+从中介点到达城市Vk的距离相比)如果能,则将那个最短距离覆盖到对应的城市上(因为开放了从Vk 出发的边, 因此有了改善某些城市最短距离的可能, 且当前只有Vk 能够优化这个最短距离)。

邻接表

#include<bits/stdc++.h>
using namespace std;
const int maxv=1010;
const int INF=1e9;
map<int,int>adj[maxv];//编号adj[x][y]=z为x点->y点,z数为边权
int n,m,s;
int d[maxv];//最短距离d
bool vis[maxv]={false};//城市集合S(编号0~n-1)

void Dijkstra(int s)
{
    fill(d,d+n,INF);//初始化
    d[s]=0;//起点s到自己本身距离为0
    for(int i=0;i<n;i++){//循环n次,每次找一个城市攻占,n次后所有城市就都被找过了
    //①找最佳点
        int u=-1,MIN=INF;//u是d中的最短的最佳点,MIN存放这个最小的d[u]
        for(int j=0;j<n;j++){
            if(!vis[j]&&d[j]<MIN){//未攻占,且距离更小更佳
                u=j;
                MIN=d[j];
            }
        }
        //第一次总是先攻占起点s,因为只改变了起点s的最短距离d[s]=0

     //②以最佳点为中介点进行优化
        //找不到小于INF的d[u],说明剩下的顶点和起点s不连通
        if(u==-1)return;
        vis[u]=true;
        for(map<int,int>::iterator j=adj[u].begin();j!=adj[u].end();j++){
            //如果未被访问
            //且以u为中介点的距离(经过中介点d[u]再到达j 点j->second<d[v])更短,则优化
            if(!vis[j->first]&&(d[u]+j->second<d[j->first])){
                d[j->first]=d[u]+j->second;//优化
            }
        }
    }
}
int main() {
    int x,y,z;
    scanf("%d %d %d",&n,&m,&s);
    for(int i=0;i<m;i++){
        scanf("%d %d %d",&x,&y,&z);
        adj[x][y]=z;
    }
    Dijkstra(s);
    for(int i=0;i<n;i++)
        printf("%d ",d[i]);
    return 0;
}

邻接矩阵

#include <bits/stdc++.h>
using namespace std;
const int MAXV = 1000; //最大顶点数
const int INF= 1e9; //设INF为一个很大的数
int n, m, s, G [MAXV] [MAXV]; //n为顶点数, m为边数, s为起点
int d[MAXV] ;//起点到达各点的最短路径长度
bool vis[MAXV] = {false}; //标记数组,vis[i]==true表示已访问。初值均为false

void Dijkstra(int s) { //s为起点
    fill (d, d + MAXV, INF); //fill函数将整个d 数组赋为INF (慎用memset)
    d[s] = 0; //起点s 到达自身的距离为0
    for(int i = 0; i < n; i++) { //循环n次
    //循环n次保证每次抢占一个城市,最后都抢占完
        //步骤①
        int u = -1, MIN = INF; //u使d[u]最小,MIN存放该最小的d[u]
        for(int j = 0; j < n; j++) {
            if(vis[j] == false && d[j]<MIN) { //找到未访问的顶点中d[u]最小的
                u = j;
                MIN = d [j];
            }
        }
            //步骤②
            //找不到小于INF 的d[u], 说明剩下的顶点和起点s不连通
            if(u ==-1)
                return;
            vis[u] = true; //标记u为己访问
            for(int v = 0; v < n; v++) {
                //如果v未访问&& u能到达V &&以u为中介点可以使d[v]更优
                if(vis[v] == false && G[u][v] != INF && d[u] + G[u][v] < d[v])
                       d[v] = d[u] + G[u][v]; //优化d[v]
            }
    }
}
int main() {
    int u, v, w;
    scanf("%d %d %d", &n, &m, &s); //顶点个数、边数、起点编号
    fill(G[0], G[0] + MAXV * MAXV, INF); //初始化图G
    for(int i = 0 ; i < m; i++) {
        scanf ("%d %d %d", &u, &v, &w);
        //输入u,v以及u->v的边权
        G[u] [v] = w;
    }
    Dijkstra(s); //Dijkstra算法入口
    for(int i = 0; i < n; i++)
        printf("%d ", d[i]); //输出所有顶点的最短距离-
    return 0;
}

1003 Emergency (25分)(涉及第二标尺)

https://pintia.cn/problem-sets/994805342720868352/problems/994805523835109376

  As an emergency rescue team leader of a city, you are given a special map of your country. The map shows several scattered cities connected by some roads. Amount of rescue teams in each city and the length of each road between any pair of cities are marked on the map. When there is an emergency call to you from some other city, your job is to lead your men to the place as quickly as possible, and at the mean time, call up as many hands on the way as possible.

Input Specification:
Each input file contains one test case. For each test case, the first line contains 4 positive integers: N (≤500) - the number of cities (and the cities are numbered from 0 to N−1), M - the number of roads, C​1 and C2 - the cities that you are currently in and that you must save, respectively. The next line contains N integers, where the i-th integer is the number of rescue teams in the i-th city. Then M lines follow, each describes a road with three integers c​1, c​2 and L, which are the pair of cities connected by a road and the length of that road,respectively. It is guaranteed that there exists at least one path from C1 to C2 .

Output Specification:
For each test case, print in one line two numbers: the number of different shortest paths between C1 and C2
​​ , and the maximum amount of rescue teams you can possibly gather. All the numbers in a line must be separated by exactly one space, and there is no extra space allowed at the end of a line.

Sample Input:
5 6 0 2
1 2 1 5 3
0 1 1
0 2 2
0 3 1
1 2 1
2 4 1
3 4 1

Sample Output:
2 4

邻接表

#include<bits/stdc++.h>
using namespace std;
const int maxv = 1000;
const int INF = 1e9;
int n, m, c1, c2;//城市数(0~n-1);道路(无向边);起点;终点
map<int, int>adj[maxv];//图
map<int, int>P;//点权集合
int d[maxv];//最短距离
bool vis[maxv] = { false };//城市访问集合S

int num[maxv], w[maxv];//最短路径条数;最大点权和

void Dijkstra(int s)
{
	fill(d, d + n, INF);
	d[s] = 0;
	fill(num, num + n, 0);
	num[s] = 1;
	fill(w, w + n, 0);
	w[s] = P[s];
	for (int i = 0; i<n; i++){//循环n遍
		int u = -1, MIN = INF;
		for (int j = 0; j<n; j++){
			if (!vis[j] && d[j]<MIN){
				u = j;
				MIN = d[j];
			}
		}

		if (u == -1)return;
		vis[u] = true;
		for (map<int, int>::iterator it = adj[u].begin(); it != adj[u].end(); it++){
			int v = it->first, dis = it->second;
			if (!vis[v]){
				//第一标尺
				if (d[u] + dis<d[v]){
					d[v] = d[u] + dis;//优化最短距离
					num[v] = num[u];//覆盖最短路径条数
					w[v] = w[u] + P[v];//叠加当前最大点权和
				}
				//第二标尺
				else if (d[u] + dis == d[v]){
					num[v] += num[u];//最短路径条数累加
					if (w[u] + P[v]>w[v])//最大点权
						w[v] = w[u] + P[v];
				}
			}
		}
	}
}
int main() {
	int x, y, z;
	scanf("%d %d %d %d", &n, &m, &c1, &c2);
	for (int i = 0; i<n; i++)
		scanf("%d", &P[i]);
	for (int i = 0; i<m; i++){
		scanf("%d %d %d", &x, &y, &z);
		adj[x][y] = z;
		adj[y][x] = z;
	}
	Dijkstra(c1);
	printf("%d %d\n", num[c2], w[c2]);
	return 0;
}

1030 Travel Plan (30分)

https://pintia.cn/problem-sets/994805342720868352/problems/994805464397627392
  A traveler’s map gives the distances between cities along the highways, together with the cost of each highway. Now you are supposed to write a program to help a traveler to decide the shortest path between his/her starting city and the destination. If such a shortest path is not unique, you are supposed to output the one with the minimum cost, which is guaranteed to be unique.

Input Specification:
  Each input file contains one test case. Each case starts with a line containing 4 positive integers N, M, S, and D, where N (≤500) is the number of cities (and hence the cities are numbered from 0 to N−1); M is the number of highways; S and D are the starting and the destination cities, respectively. Then M lines follow, each provides the information of a highway, in the format:

City1 City2 Distance Cost

where the numbers are all integers no more than 500, and are separated by a space.

Output Specification:
  For each test case, print in one line the cities along the shortest path from the starting point to the destination, followed by the total distance and the total cost of the path. The numbers must be separated by a space and there must be no extra space at the end of output.

Sample Input:
4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20

Sample Output:
0 2 3 3 40

只用Dijkstra的方法
#include<bits/stdc++.h>
using namespace std;
const int INF=1e9;
const int maxv=1000;
int N,M,S,D;
map<int,int>adj[maxv],cost[maxv];
int d[maxv],Cost[maxv],pre[maxv];
bool vis[maxv]={false};

void Dijkstra(int s)
{
    fill(d,d+N,INF);
    fill(Cost,Cost+N,INF);
    for(int i=0;i<N;i++)
        pre[i]=i;
    d[s]=0;
    Cost[s]=0;

    for(int i=0;i<N;i++){
        int u=-1,MIN=INF;
        for(int j=0;j<N;j++){
            if(!vis[j]&&d[j]<MIN){
                u=j;
                MIN=d[j];
            }
        }

        if(u==-1)return;
        vis[u]=true;
        for(map<int,int>::iterator it=adj[u].begin();it!=adj[u].end();it++){
            int v=it->first,dis=it->second,c=cost[u][it->first];
            if(!vis[v]&&((d[u]+dis<d[v]))||(d[u]+dis==d[v]&&Cost[u]+c<Cost[v])){
                    d[v]=d[u]+dis;
                    Cost[v]=Cost[u]+c;
                    pre[v]=u;
            }
        }
    }


}
int main() {
    int x,y,z,h;
    scanf("%d %d %d %d",&N,&M,&S,&D);
    for(int i=0;i<M;i++){
        scanf("%d %d %d %d",&x,&y,&z,&h);
        adj[x][y]=z;
        cost[x][y]=h;
        adj[y][x]=z;
        cost[y][x]=h;
    }
    Dijkstra(S);
    int path[maxv],t=0,p=D;
    while(p!=S){
        path[t++]=p;
        p=pre[p];
    }
    path[t]=p;
    for(int i=t;i>=0;i--)
        printf("%d ",path[i]);
    printf("%d %d\n",d[D],Cost[D]);
    return 0;
}

Dijkstra+DFS求出所有最佳路径再判断第二标尺
注意
  1. STL容器可以直接用=赋值
  2. DFS中到达边界(起点)的时候也需要把边界加入暂时路径中,所以判断完之后,同样也需要回溯,否则不能达到DFS的目的
  3. 在到达边界中,判定完之后注意要return退出
AC代码
#include<bits/stdc++.h>
using namespace std;
const int INF=1e9;
const int maxv=1000;
int N,M,S,D;
map<int,int>adj[maxv],cost[maxv];
int d[maxv];
bool vis[maxv]={false};

int optcost=INF;//第二标尺最优值
vector<int>pre[maxv];//每个节点可能存在多个前驱节点
vector<int>path,tempPath;//最优路径,临时路径

void DFS(int v)//v为当前访问节点
{
    //递归边界
    if(v==S){//到达了叶子节点(起点S)
        tempPath.push_back(v);
        int value=0;
        for(int i=tempPath.size()-1;i>=0;i--){//因为是递归获得的路径,所以是逆序的
            int now=tempPath[i],next=tempPath[i-1];
            value+=cost[now][next];
        }
        if(value<optcost){
            optcost=value;
            path=tempPath;//保存的也是逆序的
        }
        tempPath.pop_back();//注意,在边界中也要注意有回溯
        return;//注意退出!!
    }

    //递归式,加入该点,然后根据多个前驱寻找下一点(分支成树)再加入
    tempPath.push_back(v);//加入到队尾
    for(int i=0;i<pre[v].size();i++)
        DFS(pre[v][i]);
    tempPath.pop_back();//回溯
}
void Dijkstra(int s)
{
    fill(d,d+N,INF);
    d[s]=0;
    for(int i=0;i<N;i++){
        int u=-1,MIN=INF;
        for(int j=0;j<N;j++){
            if(!vis[j]&&d[j]<MIN){
                u=j;
                MIN=d[j];
            }
        }

        if(u==-1)return;
        vis[u]=true;
        for(map<int,int>::iterator it=adj[u].begin();it!=adj[u].end();it++){
            int v=it->first,dis=it->second,c=cost[u][it->first];
            if(!vis[v]){
                if(d[u]+dis<d[v]){
                    pre[v].clear();//优化了路线(不从之前的前驱经过了)
                    d[v]=d[u]+dis;
                    pre[v].push_back(u);
                }
                else if(d[u]+dis==d[v]){//同样满足第一标尺那么添加前驱节点
                    pre[v].push_back(u);
                }
            }
        }
    }


}
int main() {
    int x,y,z,h;
    scanf("%d %d %d %d",&N,&M,&S,&D);
    for(int i=0;i<M;i++){
        scanf("%d %d %d %d",&x,&y,&z,&h);
        adj[x][y]=z;
        cost[x][y]=h;
        adj[y][x]=z;
        cost[y][x]=h;
    }
    Dijkstra(S);
    DFS(D);
    for(int i=path.size()-1;i>=0;i--)
        printf("%d ",path[i]);
    printf("%d %d\n",d[D],optcost);

    return 0;
}

7-4 Dijkstra Sequence (30分)

  Dijkstra’s algorithm is one of the very famous greedy algorithms. It is used for solving the single source shortest path problem which gives the shortest paths from one particular source vertex to all the other vertices of the given graph. It was conceived by computer scientist Edsger W. Dijkstra in 1956 and published three years later.

  In this algorithm, a set contains vertices included in shortest path tree is maintained. During each step, we find one vertex which is not yet included and has a minimum distance from the source, and collect it into the set. Hence step by step an ordered sequence of vertices, let’s call it Dijkstra sequence, is generated by Dijkstra’s algorithm.

  On the other hand, for a given graph, there could be more than one Dijkstra sequence. For example, both { 5, 1, 3, 4, 2 } and { 5, 3, 1, 2, 4 } are Dijkstra sequences for the graph, where 5 is the source. Your job is to check whether a given sequence is Dijkstra sequence or not.

Input Specification:
Each input file contains one test case. For each case, the first line contains two positive integers Nv(≤10^3
​​ ) and Ne(≤10^5), which are the total numbers of vertices and edges, respectively. Hence the vertices are numbered from 1 to Nv.

  Then Ne lines follow, each describes an edge by giving the indices of the vertices at the two ends, followed by a positive integer weight (≤100) of the edge. It is guaranteed that the given graph is connected.

Finally the number of queries, K, is given as a positive integer no larger than 100, followed by K lines of sequences, each contains a permutationof the Nv​​ vertices. It is assumed that the first vertex is the source for each sequence.

All the inputs in a line are separated by a space.

Output Specification:
For each of the K sequences, print in a line Yes if it is a Dijkstra sequence, or No if not.

Sample Input:
5 7
1 2 2
1 5 1
2 3 1
2 4 1
2 5 2
3 5 1
3 4 1
4
5 1 3 4 2
5 3 1 2 4
2 3 4 5 1
3 2 1 5 4

Sample Output:
Yes
Yes
Yes
No

省题

  Dijkstra sequence是指这样一个攻占顺序能求得起点到达所有点的最短路径
Dijkstra sequence地杰斯特拉算法的过程是
    当前未攻占过的顶点中,距离最短的点为最佳攻占点(若有多个点选其中一点即可)
    然后攻占n次把所有城市都遍历到,走过的这一条路径即为最短路径
    最短路径可能有多条(若有多个最佳攻占点就会分支为多条路)
  这题就是判断输入的路径是否为dijkstra的最短路径

思路

和原来的Dijkstra的步骤相仿,但是每次选择攻占的城市都为既定的序列中的顶点u=path[i]

//让下一个攻占的城市假设就为预设的path[i]
//若有比path[i]路径更短的,说明path[i]不是最佳攻占点,那么这个就不是dijsktra序列

//是找攻占城市的过程,那不如假设就是序列中对应的城市,看它是否满足最佳攻占条件
int u=path[i],MIN=d[path[i]];
for(int j=1; j<=n; j++)
 if(!vis[j]&&d[j]<MIN)
  return false;

bool Dijkstra(int s) {
    fill(vis,vis+n,false);
    fill(d,d+n,INF);
    d[s]=0;
    for(int i=0; i<n; i++) {
        //让下一个攻占的城市假设就为预设的path[i]
        //若有比path[i]路径更短的,说明path[i]不是最佳攻占点,那么这个就不是dijsktra序列

        //是找攻占城市的过程,那不如假设就是序列中对应的城市,看它是否满足最佳攻占条件
        int u=path[i],MIN=d[path[i]];
        for(int j=1; j<=n; j++)
            if(!vis[j]&&d[j]<MIN)
                return false;

        vis[u]=true;
        for(map<int,int>::iterator it=mp[u].begin(); it!=mp[u].end(); it++) {
            int v=it->first,dis=it->second;
            if(!vis[v]&&d[u]+dis<d[v]) {
                d[v]=d[u]+dis;
            }
        }
    }
    return true;
}

AC代码

#include <bits/stdc++.h>
using namespace std;
const int maxv=1010;
const int INF=1e9;
map<int,int>mp[maxv];
int n,m,k,path[maxv],d[maxv];
bool vis[maxv];

bool Dijkstra(int s) {
    fill(vis,vis+n,false);
    fill(d,d+n,INF);
    d[s]=0;
    for(int i=0; i<n; i++) {
        //让下一个攻占的城市假设就为预设的path[i]
        //若有比path[i]路径更短的,说明path[i]不是最佳攻占点,那么这个就不是dijsktra序列

        //是找攻占城市的过程,那不如假设就是序列中对应的城市,看它是否满足最佳攻占条件
        int u=path[i],MIN=d[path[i]];
        for(int j=1; j<=n; j++)
            if(!vis[j]&&d[j]<MIN)
                return false;

        vis[u]=true;
        for(map<int,int>::iterator it=mp[u].begin(); it!=mp[u].end(); it++) {
            int v=it->first,dis=it->second;
            if(!vis[v]&&d[u]+dis<d[v]) {
                d[v]=d[u]+dis;
            }
        }
    }
    return true;
}
int main() {
    scanf("%d %d",&n,&m);
    int x,y,z;
    for(int i=0; i<m; i++) {
        scanf("%d %d %d",&x,&y,&z);
        mp[x][y]=mp[y][x]=z;
    }
    scanf("%d",&k);
    for(int i=0; i<k; i++) {
        for(int j=0; j<n; j++)
            scanf("%d",&path[j]);
        if(Dijkstra(path[0]))
            printf("Yes\n");
        else
            printf("No\n");
    }
    return 0;
}

别人的写法

  在寻找最佳点时,保留所有最佳点,若当前选择的攻占点在最佳点序列中则符合,接着选择该点作为攻占点优化;若不在当前序列中,则不符合退出

void check() {
fill(d + 1, d + 1 + n, INF);
fill(vis + 1, vis + 1 + n, false);
d[now[0]] = 0;
set tmp;
int index = 0;
for (int i = 0; i < n; i++) {
int u, mini = INF;
for (int j = 1; j <= n; j++)
if (vis[j] == false) {
   if (d[j] < mini) {//更新最佳点
       mini = d[j];
       tmp.clear();
       tmp.insert(j);
   } else if (d[j] == mini)//同为最佳点,添加
     tmp.insert(j);
}

if (tmp.find(now[index]) != tmp.end()) {//不在当前序列中
vis[now[index]] = true;
u = now[index];
tmp.clear();
} else {
cout << “No” << endl;
return;
}
for (int j = 1; j <= n; j++)
if (vis[j] == false && matrx[u][j] != 0 && d[j] > d[u] + matrx[u][j])
d[j] = d[u] + matrx[u][j];
index++;
}
cout << “Yes” << endl;
}

#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
#include <string>
#include <unordered_map>
#include <math.h>
#define maxsize 1002
#define INF 99999999
using namespace std;
int n, m, matrx[maxsize][maxsize] = {0}, d[maxsize];
bool vis[maxsize] = {false};
vector<int> now;
void check() {
    fill(d + 1, d + 1 + n, INF);
    fill(vis + 1, vis + 1 + n, false);
    d[now[0]] = 0;
    set<int> tmp;
    int index = 0;
    for (int i = 0; i < n; i++) {
        int u, mini = INF;
        for (int j = 1; j <= n; j++)
            if (vis[j] == false) {
                if (d[j] < mini) {
                    mini = d[j];
                    tmp.clear();
                    tmp.insert(j);
                } else if (d[j] == mini)
                    tmp.insert(j);
            }
        if (tmp.find(now[index]) != tmp.end()) {
            vis[now[index]] = true;
            u = now[index];
            tmp.clear();
        } else {
            cout << "No" << endl;
            return;
        }
        for (int j = 1; j <= n; j++)
            if (vis[j] == false && matrx[u][j] != 0 && d[j] > d[u] + matrx[u][j])
                d[j] = d[u] + matrx[u][j];
        index++;
    }
    cout << "Yes" << endl;
}
int main() {
    std::iostream::sync_with_stdio(false);
    std::cin.tie(0);

    cin >> n >> m;
    int a, b, c;
    for (int i = 0; i < m; i++) {
        cin >> a >> b >> c;
        matrx[a][b] = matrx[b][a] = c;
    }
    cin >> m;
    for (int i = 0; i < m; i++) {
        now.clear();
        for (int j = 0; j < n; j++) {
            cin >> a;
            now.push_back(a);
        }
        check();
    }
    return 0;
}

Floyd算法(全源最短路问题)(非递归)

  和Dijkstra算法相似,不过是把单源覆盖到全源,所以不再需要把最短路径集dis和图集S分开了,一开始输入的边就可直接写入dis中
  Floyd算法(读者可以将其读作”弗洛伊德算法")用来解决全源最短路问题,即对给定的图G(V,E), 求任意两点U, V之间的最短路径长度,时间复杂度是O( n^3 )。由于 n^3 的复杂度决定了顶点数n的限制约在200 以内,因此使用邻接矩阵来实现Floyd算法是非常合适且方便的。
注意

  1. 初始化要把距离fill成INF,再把其中点自己到自己的距离设为0
  2. 在floyd算法中,循环中介点k, 顶点i, 和顶点j三个的全排列找到任何两点的最短路径
  3. dis[maxv]变为dis[maxv][maxv]

数码宝贝拯救者

题目如上,从单源改为全源,输出每个点的到每个点的最短距离

#include <bits/stdc++.h>
using namespace std;
const int INF = 1e9;
const int MAXV = 200; //MAXV 为最大顶点数
int n, m; //n 为顶点数, m 为边数
int dis[MAXV][MAXV]; //dis[i][j]表示顶点i 和顶点j 的最短距离

void floyd() {
    for(int k=0; k<n; k++)
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
                if(dis[i][k]!=INF&&dis[k][j]!=INF&&dis[i][k]+dis[k][j]<dis[i][j])
                    dis[i][j]=dis[i][k]+dis[k][j];
}
int main () {
    scanf("%d %d",&n,&m);
    int x,y,z;
    fill(dis[0],dis[0]+MAXV*MAXV,INF);
    for(int i=0; i<n; i++)
        dis[i][i]=0;

    for(int i=0; i<m; i++) {
        scanf("%d %d %d",&x,&y,&z);
        dis[x][y]=z;
    }
    floyd();
    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++)
            printf("%d%s",dis[i][j],j==(n-1)?"\n":" ");
    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Deosiree

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值