最短路徑

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章