日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

数据结构--图(Graph)详解(四)

發(fā)布時間:2024/4/11 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构--图(Graph)详解(四) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

數(shù)據(jù)結(jié)構(gòu)–圖(Graph)詳解(四)

文章目錄

  • 數(shù)據(jù)結(jié)構(gòu)--圖(Graph)詳解(四)
    • 一、圖中幾個NB的算法
      • 1.普里姆算法(Prim算法)求最小生成樹
      • 2.克魯斯卡爾算法(Kruskal算法)求最小生成樹
      • 3.拓?fù)渑判蛩惴?/li>
      • 4.迪杰斯特拉(Dijkstra算法)算法
      • 5.弗洛伊德算法

一、圖中幾個NB的算法

1.普里姆算法(Prim算法)求最小生成樹

普里姆算法(Prim算法)求最小生成樹:https://blog.csdn.net/wolfGuiDao/article/details/107588112

該算法從頂點的角度為出發(fā)點,時間復(fù)雜度為O(n2),更適合與解決邊的綢密度更高的連通網(wǎng)。

2.克魯斯卡爾算法(Kruskal算法)求最小生成樹

  • 克魯斯卡爾算法,從邊的角度求網(wǎng)的最小生成樹,時間復(fù)雜度為O(eloge)。和普里姆算法恰恰相反,更適合于求邊稀疏的網(wǎng)的最小生成樹。
  • 對于任意一個連通網(wǎng)的最小生成樹來說,在要求總的權(quán)值最小的情況下,最直接的想法就是將連通網(wǎng)中的所有邊按照權(quán)值大小進(jìn)行升序排序,從小到大依次選擇。
  • 由于最小生成樹本身是一棵生成樹,所以需要時刻滿足以下兩點:
  • 生成樹中任意頂點之間有且僅有一條通路,也就是說,生成樹中不能存在回路;
  • 對于具有 n 個頂點的連通網(wǎng),其生成樹中只能有 n-1 條邊,這 n-1 條邊連通著 n 個頂點。
  • 連接 n 個頂點在不產(chǎn)生回路的情況下,只需要 n-1 條邊。
  • 所以克魯斯卡爾算法的具體思路是:將所有邊按照權(quán)值的大小進(jìn)行升序排序,然后從小到大一一判斷
  • 條件為:如果這個邊不會與之前選擇的所有邊組成回路,就可以作為最小生成樹的一部分;反之,舍去。
  • 直到具有 n 個頂點的連通網(wǎng)篩選出來 n-1 條邊為止。篩選出來的邊和所有的頂點構(gòu)成此連通網(wǎng)的最小生成樹。
  • 判斷是否會產(chǎn)生回路的方法為:在初始狀態(tài)下給每個頂點賦予不同的標(biāo)記,對于遍歷過程的每條邊,其都有兩個頂點,判斷這兩個頂點的標(biāo)記是否一致,如果一致,說明它們本身就處在一棵樹中,如果繼續(xù)連接就會產(chǎn)生回路;如果不一致,說明它們之間還沒有任何關(guān)系,可以連接(也可以使用并查集來判斷)。

假設(shè)遍歷到一條由頂點 A 和 B 構(gòu)成的邊,而頂點 A 和頂點 B 標(biāo)記不同,此時不僅需要將頂點 A 的標(biāo)記更新為頂點 B 的標(biāo)記,還需要更改所有和頂點 A 標(biāo)記相同的頂點的標(biāo)記,全部改為頂點 B 的標(biāo)記。

  • 例如,使用克魯斯卡爾算法找圖 1 的最小生成樹的過程為:
  • 首先,在初始狀態(tài)下,對各頂點賦予不同的標(biāo)記(用顏色區(qū)別),如下圖所示:

  • 對所有邊按照權(quán)值的大小進(jìn)行排序,按照從小到大的順序進(jìn)行判斷,首先是(1,3)
  • 由于頂點 1 和頂點 3 標(biāo)記不同,所以可以構(gòu)成生成樹的一部分,遍歷所有頂點,將與頂點 3 標(biāo)記相同的全部更改為頂點 1 的標(biāo)記,如(2)所示:
  • 其次是(4,6)邊,兩頂點標(biāo)記不同,所以可以構(gòu)成生成樹的一部分,更新所有頂點的標(biāo)記為:

  • 其次是(2,5)邊,兩頂點標(biāo)記不同,可以構(gòu)成生成樹的一部分,更新所有頂點的標(biāo)記為:

  • 然后最小的是(3,6)邊,兩者標(biāo)記不同,可以連接,遍歷所有頂點,將與頂點 6 標(biāo)記相同的所有頂點的標(biāo)記更改為頂點 1 的標(biāo)記:

  • 繼續(xù)選擇權(quán)值最小的邊,此時會發(fā)現(xiàn),權(quán)值為 5 的邊有 3 個,其中(1,4)和(3,4)各自兩頂點的標(biāo)記一樣,如果連接會產(chǎn)生回路,所以舍去
  • 而(2,3)標(biāo)記不一樣,可以選擇,將所有與頂點 2 標(biāo)記相同的頂點的標(biāo)記全部改為同頂點 3 相同的標(biāo)記:
  • 當(dāng)選取的邊的數(shù)量相比與頂點的數(shù)量小 1 時,說明最小生成樹已經(jīng)生成。所以最終采用克魯斯卡爾算法得到的最小生成樹為(6)所示
#include "stdio.h" #include "stdlib.h" #define MAX_VERtEX_NUM 20 #define VertexType inttypedef struct edge{VertexType initial;VertexType end;VertexType weight; }edge[MAX_VERtEX_NUM];//定義輔助數(shù)組 typedef struct {VertexType value;//頂點數(shù)據(jù)int sign;//每個頂點所屬的集合 }assist[MAX_VERtEX_NUM]; assist assists;//qsort排序函數(shù)中使用,使edges結(jié)構(gòu)體中的邊按照權(quán)值大小升序排序 int cmp(const void *a,const void*b){return ((struct edge*)a)->weight-((struct edge*)b)->weight; }//初始化連通網(wǎng) void CreateUDN(edge *edges,int *vexnum,int *arcnum){printf("輸入連通網(wǎng)的邊數(shù):\n");scanf("%d %d",&(*vexnum),&(*arcnum));printf("輸入連通網(wǎng)的頂點:\n");for (int i=0; i<(*vexnum); i++) {scanf("%d",&(assists[i].value));assists[i].sign=i;}printf("輸入各邊的起始點和終點及權(quán)重:\n");for (int i=0 ; i<(*arcnum); i++) {scanf("%d,%d,%d",&(*edges)[i].initial,&(*edges)[i].end,&(*edges)[i].weight);} }//在assists數(shù)組中找到頂點point對應(yīng)的位置下標(biāo) int Locatevex(int vexnum,int point){for (int i=0; i<vexnum; i++) {if (assists[i].value==point) {return i;}}return -1; }int main(){int arcnum,vexnum;edge edges;CreateUDN(&edges,&vexnum,&arcnum);//對連通網(wǎng)中的所有邊進(jìn)行升序排序,結(jié)果仍保存在edges數(shù)組中qsort(edges, arcnum, sizeof(edges[0]), cmp);//創(chuàng)建一個空的結(jié)構(gòu)體數(shù)組,用于存放最小生成樹edge minTree;//設(shè)置一個用于記錄最小生成樹中邊的數(shù)量的常量int num=0;//遍歷所有的邊for (int i=0; i<arcnum; i++) {//找到邊的起始頂點和結(jié)束頂點在數(shù)組assists中的位置int initial=Locatevex(vexnum, edges[i].initial);int end=Locatevex(vexnum, edges[i].end);//如果頂點位置存在且頂點的標(biāo)記不同,說明不在一個集合中,不會產(chǎn)生回路if (initial!=-1&& end!=-1&&assists[initial].sign!=assists[end].sign) {//記錄該邊,作為最小生成樹的組成部分minTree[num]=edges[i];//計數(shù)+1num++;//將新加入生成樹的頂點標(biāo)記全不更改為一樣的for (int k=0; k<vexnum; k++) {if (assists[k].sign==assists[end].sign) {assists[k].sign=assists[initial].sign;}}//如果選擇的邊的數(shù)量和頂點數(shù)相差1,證明最小生成樹已經(jīng)形成,退出循環(huán)if (num==vexnum-1) {break;}}}//輸出語句for (int i=0; i<vexnum-1; i++) {printf("%d,%d\n",minTree[i].initial,minTree[i].end);}return 0; }

3.拓?fù)渑判蛩惴?/h3>
  • 拓?fù)渑判蛑傅氖菍⒂邢驘o環(huán)圖(又稱“DAG”圖)中的頂點按照圖中指定的先后順序進(jìn)行排序。
  • 在圖論中,由一個有向無環(huán)圖的頂點組成的序列,當(dāng)且僅當(dāng)滿足下列條件時,稱為該圖的一個拓?fù)渑判?/strong>
  • 每個頂點出現(xiàn)且只出現(xiàn)一次;
  • 若存在一條從頂點 A 到頂點 B 的路徑,那么在序列中頂點 A 出現(xiàn)在頂點 B 的前面。

  • 例如,圖 1 中的兩個圖都是有向無環(huán)圖,都可以使用拓?fù)渑判驅(qū)D中的頂點進(jìn)行排序

  • 兩個圖形的區(qū)別是:左圖中的 V2 和 V3 之間沒有明確的前后順序;而右圖中任意兩個頂點之間都有前后順序。

  • 所以,左圖中頂點之間的關(guān)系被稱為“偏序”關(guān)系;右圖中頂點之間的關(guān)系被稱為”全序“關(guān)系。

在有向無環(huán)圖中,弧的方向代表著頂點之間的先后次序,例如從 V1 指向 V2 的弧表示在進(jìn)行排序時 V1 在前, V2 在后。

全序是偏序的一種特殊情況。對于任意一個有向無環(huán)圖來說,通過拓?fù)渑判虻玫降男蛄惺紫纫欢ㄊ瞧?#xff0c;如果任意兩個頂點都具有前后順序,那么此序列是全序。

  • 拓?fù)渑判虻姆椒?/strong>
    對有向無環(huán)圖進(jìn)行拓?fù)渑判?#xff0c;只需要遵循兩個原則:
  • 在圖中選擇一個沒有前驅(qū)的頂點 V(即入度為0);
  • 從圖中刪除頂點 V 和所有以該頂點為尾的弧(刪除該頂點和所有以它為起點的有向邊)。

例如,在對圖 1 中的左圖進(jìn)行拓?fù)渑判驎r的步驟如圖 2 所示

有向無環(huán)圖如果頂點本身具有某種實際意義,例如用有向無環(huán)圖表示大學(xué)期間所學(xué)習(xí)的全部課程,每個頂點都表示一門課程,有向邊表示課程學(xué)習(xí)的先后次序

例如要先學(xué)《程序設(shè)計基礎(chǔ)》和《離散數(shù)學(xué)》,然后才能學(xué)習(xí)《數(shù)據(jù)結(jié)構(gòu)》。所以用來表示某種活動間的優(yōu)先關(guān)系的有向圖簡稱為“AOV網(wǎng)”。

  • 進(jìn)行拓?fù)渑判驎r,首先找到?jīng)]有前驅(qū)的頂點 V1,如圖 2(1)所示;
  • 在刪除頂點 V1 及以 V1 作為起點的弧后,繼續(xù)查找沒有前驅(qū)的頂點,此時, V2 和 V3 都符合條件,可以隨機(jī)選擇一個,例如圖 2(2) 所示,選擇 V2
  • 然后繼續(xù)重復(fù)以上的操作,直至最后找不到?jīng)]有前驅(qū)的頂點。

所以,針對圖 2 來說,拓?fù)渑判蜃詈蟮玫降男蛄杏袃煞N:

V1 -> V2 -> V3 -> V4 V1 -> V3 -> V2 -> V4
  • 如果頂點之間只是具有偏序關(guān)系,那么拓?fù)渑判虻慕Y(jié)果肯定不唯一;如果頂點之間是全序關(guān)系,那么拓?fù)渑判虻玫降男蛄形ㄒ弧?/strong>
  • 拓?fù)渑判虻腃語言實現(xiàn)
  • 大致思路為:首先通過鄰接表將 AOV 網(wǎng)進(jìn)行存儲,由于拓?fù)渑判虻恼麄€過程中,都是以頂點的入度為依據(jù)進(jìn)行排序,所以需要根據(jù)建立的鄰接表統(tǒng)計出各頂點的入度。
  • 在得到各頂點的入度后,首先找到入度為 0 的頂點作為拓?fù)渑判虻钠鹗键c
  • 然后查找以該頂點為起始點的所有頂點,如果入度為 1,說明如果刪除前一個頂點后,該頂點的入度為 0,為拓?fù)渑判虻南乱粋€對象。
#include <stdio.h> #include <stdlib.h> #define MAX_VERTEX_NUM 20//最大頂點個數(shù) #define VertexType int//頂點數(shù)據(jù)的類型typedef enum{false,true} bool;typedef struct ArcNode{int adjvex;//鄰接點在數(shù)組中的位置下標(biāo)struct ArcNode * nextarc;//指向下一個鄰接點的指針 }ArcNode;typedef struct VNode{VertexType data;//頂點的數(shù)據(jù)域ArcNode * firstarc;//指向鄰接點的指針 }VNode,AdjList[MAX_VERTEX_NUM];//存儲各鏈表頭結(jié)點的數(shù)組typedef struct {AdjList vertices;//圖中頂點及各鄰接點數(shù)組int vexnum,arcnum;//記錄圖中頂點數(shù)和邊或弧數(shù) }ALGraph;//找到頂點對應(yīng)在鄰接表數(shù)組中的位置下標(biāo) int LocateVex(ALGraph G,VertexType u){for (int i=0; i<G.vexnum; i++) {if (G.vertices[i].data==u) {return i;}}return -1; }//創(chuàng)建AOV網(wǎng),構(gòu)建鄰接表 void CreateAOV(ALGraph **G){*G=(ALGraph*)malloc(sizeof(ALGraph));scanf("%d,%d",&((*G)->vexnum),&((*G)->arcnum));for (int i=0; i<(*G)->vexnum; i++) {scanf("%d",&((*G)->vertices[i].data));(*G)->vertices[i].firstarc=NULL;}VertexType initial,end;for (int i=0; i<(*G)->arcnum; i++) {scanf("%d,%d",&initial,&end);ArcNode *p=(ArcNode*)malloc(sizeof(ArcNode));p->adjvex=LocateVex(*(*G), end);p->nextarc=NULL;int locate=LocateVex(*(*G), initial);p->nextarc=(*G)->vertices[locate].firstarc;(*G)->vertices[locate].firstarc=p;} }//結(jié)構(gòu)體定義棧結(jié)構(gòu) typedef struct stack{VertexType data;struct stack * next; }stack;//初始化棧結(jié)構(gòu) void initStack(stack* *S){(*S)=(stack*)malloc(sizeof(stack));(*S)->next=NULL; }//判斷鏈表是否為空 bool StackEmpty(stack S){if (S.next==NULL) {return true;}return false; }//進(jìn)棧,以頭插法將新結(jié)點插入到鏈表中 void push(stack *S,VertexType u){stack *p=(stack*)malloc(sizeof(stack));p->data=u;p->next=NULL;p->next=S->next;S->next=p; }//彈棧函數(shù),刪除鏈表首元結(jié)點的同時,釋放該空間,并將該結(jié)點中的數(shù)據(jù)域通過地址傳值給變量i; void pop(stack *S,VertexType *i){stack *p=S->next;*i=p->data;S->next=S->next->next;free(p); }//統(tǒng)計各頂點的入度 void FindInDegree(ALGraph G,int indegree[]){//初始化數(shù)組,默認(rèn)初始值全部為0for (int i=0; i<G.vexnum; i++) {indegree[i]=0;}//遍歷鄰接表,根據(jù)各鏈表中結(jié)點的數(shù)據(jù)域存儲的各頂點位置下標(biāo),在indegree數(shù)組相應(yīng)位置+1for (int i=0; i<G.vexnum; i++) {ArcNode *p=G.vertices[i].firstarc;while (p) {indegree[p->adjvex]++;p=p->nextarc;}} }void TopologicalSort(ALGraph G){int indegree[G.vexnum];//創(chuàng)建記錄各頂點入度的數(shù)組FindInDegree(G,indegree);//統(tǒng)計各頂點的入度//建立棧結(jié)構(gòu),程序中使用的是鏈表stack *S;initStack(&S);//查找度為0的頂點,作為起始點for (int i=0; i<G.vexnum; i++) {if (!indegree[i]) {push(S, i);}}int count=0;//當(dāng)棧為空,說明排序完成while (!StackEmpty(*S)) {int index;//彈棧,并記錄棧中保存的頂點所在鄰接表數(shù)組中的位置pop(S,&index);printf("%d",G.vertices[index].data);++count;//依次查找跟該頂點相鏈接的頂點,如果初始入度為1,當(dāng)刪除前一個頂點后,該頂點入度為0for (ArcNode *p=G.vertices[index].firstarc; p; p=p->nextarc) {VertexType k=p->adjvex;if (!(--indegree[k])) {//頂點入度為0,入棧push(S, k);}}}//如果count值小于頂點數(shù)量,表明該有向圖有環(huán)if (count<G.vexnum) {printf("該圖有回路");return;} }int main(){ALGraph *G;CreateAOV(&G);//創(chuàng)建AOV網(wǎng)TopologicalSort(*G);//進(jìn)行拓?fù)渑判?/span>return 0; }

4.迪杰斯特拉(Dijkstra算法)算法

由荷蘭計算機(jī)科學(xué)家艾茲赫爾·戴克斯特拉在1956年提出。戴克斯特拉算法使用了廣度優(yōu)先搜索解決賦權(quán)有向圖的單源最短路徑問題。








#include <iostream> #include <bits/stdc++.h> using namespace std;#define MAX 100 #define MAXCOST 0x7fffffff //int型最大值void prim(int graph[][MAX],int n,int start,int end) {int lowcost[MAX];int mst[MAX];int sum=0;for(int i=1;i<=n;i++)//將與各點與起始點的距離存入lowcost中{lowcost[i]=graph[start][i];mst[i]=1;}mst[start]=0; //起始點被標(biāo)記for(int i=1;i<=n;i++){if(mst[end]==0)//終點被標(biāo)記結(jié)束{cout<<sum;break;}int min=MAXCOST;int minid=0;for(int j=1;j<=n;j++)//遍歷lowcost數(shù)組,找最小值{if(lowcost[j]<min && mst[j]!=0){min=lowcost[j]; //最小值minid=j; //最小值下標(biāo)}}//cout<<"V"<<mst[minid]<<"-V"<<minid<<"="<<min<<endl;sum=min;//cout<<sum<<endl;mst[minid]=0; //最小值下標(biāo)點被標(biāo)記for(int j=1;j<=n;j++)//找最小值點與各點的距離{if(graph[minid][j]==MAXCOST)//如果此點與最小值點沒有聯(lián)系(距離為最大值)則lowcost不變,跳過{continue;}else if(graph[minid][j]+sum<lowcost[j] && mst[j]!=0)//此點與最小點有聯(lián)系,并且+sum<lowcost 并且此點沒有被標(biāo)記,則賦值給lowcost{lowcost[j]=graph[minid][j]+sum;}}} }int main() {int n,m;int start,end;int graph[MAX][MAX];cin>>n>>m>>start>>end;//初始化圖Gfor(int i=1;i<=n;i++){for(int j=1;j<=n;j++){graph[i][j]=MAXCOST;}}//構(gòu)建圖Gfor(int k=1;k<=m;k++){int i,j,cost;cin>>i>>j>>cost;graph[i][j]=cost;graph[j][i]=cost;}prim(graph,n,start,end);return 0; }

5.弗洛伊德算法


暑假,小哼準(zhǔn)備去一些城市旅游。有些城市之間有公路,有些城市之間則沒有,如下圖。為了節(jié)省經(jīng)費以及方便計劃旅程,小哼希望在出發(fā)之前知道任意兩個城市之前的最短路程。

上圖中有4個城市8條公路,公路上的數(shù)字表示這條公路的長短。

請注意這些公路是單向的。我們現(xiàn)在需要求任意兩個城市之間的最短路程,也就是求任意兩個點之間的最短路徑。這個問題這也被稱為“多源最短路徑”問題。

  • 現(xiàn)在需要一個數(shù)據(jù)結(jié)構(gòu)來存儲圖的信息,我們?nèi)匀豢梢杂靡粋€4*4的矩陣(二維數(shù)組e)來存儲。
  • 比如1號城市到2號城市的路程為2,則設(shè)e[1][2]的值為2。
  • 2號城市無法到達(dá)4號城市,則設(shè)置e[2][4]的值為∞。
  • 另外此處約定一個城市自己是到自己的也是0,例如e[1][1]為0,具體如下。

  • 現(xiàn)在回到問題:如何求任意兩點之間最短路徑呢?通過之前的學(xué)習(xí)我們知道通過深度或廣度優(yōu)先搜索可以求出兩點之間的最短路徑。

  • 所以進(jìn)行n2遍深度或廣度優(yōu)先搜索,即對每兩個點都進(jìn)行一次深度或廣度優(yōu)先搜索,便可以求得任意兩點之間的最短路徑。可是還有沒有別的方法呢?

  • 我們來想一想,根據(jù)我們以往的經(jīng)驗,如果要讓任意兩點(例如從頂點a點到頂點b)之間的路程變短,只能引入第三個點(頂點k),并通過這個頂點k中轉(zhuǎn)即a->k->b,才可能縮短原來從頂點a點到頂點b的路程。

  • 那么這個中轉(zhuǎn)的頂點k是1~n中的哪個點呢?甚至有時候不只通過一個點,而是經(jīng)過兩個點或者更多點中轉(zhuǎn)會更短,即a->k1->k2b->或者a->k1->k2…->k->i…->b。

  • 比如上圖中從4號城市到3號城市(4->3)的路程e[4][3]原本是12。如果只通過1號城市中轉(zhuǎn)(4->1->3),路程將縮短為11(e[4][1]+e[1][3]=5+6=11)。

  • 其實1號城市到3號城市也可以通過2號城市中轉(zhuǎn),使得1號到3號城市的路程縮短為5(e[1][2]+e[2][3]=2+3=5)。

  • 所以如果同時經(jīng)過1號和2號兩個城市中轉(zhuǎn)的話,從4號城市到3號城市的路程會進(jìn)一步縮短為10。

  • 通過這個的例子,我們發(fā)現(xiàn)每個頂點都有可能使得另外兩個頂點之間的路程變短。好,下面我們將這個問題一般化。

  • 當(dāng)任意兩點之間不允許經(jīng)過第三個點時,這些城市之間最短路程就是初始路程,如下。

  • 假如現(xiàn)在只允許經(jīng)過1號頂點,求任意兩點之間的最短路程,應(yīng)該如何求呢?
  • 只需判斷e[i][1] + e[1][j]是否比e[i][j]要小即可。
  • e[i][j]表示的是從i號頂點到j(luò)號頂點之間的路程。e[i][1] + e[1][j]表示的是從i號頂點先到1號頂點,再從1號頂點到j(luò)號頂點的路程之和其中i是1~n循環(huán),j也是1~n循環(huán),代碼實現(xiàn)如下。
for (i = 1; i <= n; i++) {for (j = 1; j <= n; j++){if (e[i][j] > e[i][1] + e[1][j])e[i][j] = e[i][1] + e[1][j];} }
  • 在只允許經(jīng)過1號頂點的情況下,任意兩點之間的最短路程更新為:

  • 通過上圖我們發(fā)現(xiàn):在只通過1號頂點中轉(zhuǎn)的情況下,3號頂點到2號頂點(e[3][2])、4號頂點到2號頂點(e[4][2])以及4號頂點到3號頂點(e[4][3])的路程都變短了。

  • 接下來繼續(xù)求在只允許經(jīng)過1和2號兩個頂點的情況下任意兩點之間的最短路程。

  • 如何做呢?我們需要在只允許經(jīng)過1號頂點時任意兩點的最短路程的結(jié)果下,再判斷如果經(jīng)過2號頂點是否可以使得i號頂點到j(luò)號頂點之間的路程變得更短。

  • 即判斷e[i][2]+e[2][j]是否比e[i][j]要小,代碼實現(xiàn)為如下。

//經(jīng)過1號頂點 for(i=1;i<=n;i++) for(j=1;j<=n;j++) if (e[i][j] > e[i][1]+e[1][j]) e[i][j]=e[i][1]+e[1][j]; //經(jīng)過2號頂點 for(i=1;i<=n;i++) for(j=1;j<=n;j++) if (e[i][j] > e[i][2]+e[2][j]) e[i][j]=e[i][2]+e[2][j];
  • 在只允許經(jīng)過1和2號頂點的情況下,任意兩點之間的最短路程更新為:

  • 通過上圖得知,在相比只允許通過1號頂點進(jìn)行中轉(zhuǎn)的情況下,這里允許通過1和2號頂點進(jìn)行中轉(zhuǎn),使得e[1][3]和e[4][3]的路程變得更短了。

  • 同理,繼續(xù)在只允許經(jīng)過1、2和3號頂點進(jìn)行中轉(zhuǎn)的情況下,求任意兩點之間的最短路程。任意兩點之間的最短路程更新為:

  • 最后允許通過所有頂點作為中轉(zhuǎn),任意兩點之間最終的最短路程為:

#include <stdio.h>int main() {int e[10][10],k,i,j,n,m,t1,t2,t3;int inf=99999999; //用inf(infinity的縮寫)存儲一個我們認(rèn)為的正無窮值//讀入n和m,n表示頂點個數(shù),m表示邊的條數(shù)scanf("%d %d",&n,&m);//初始化for(i=1;i<=n;i++)for(j=1;j<=n;j++)if(i==j) e[i][j]=0;else e[i][j]=inf;//讀入邊for(i=1;i<=m;i++){scanf("%d %d %d",&t1,&t2,&t3);e[t1][t2]=t3;}//Floyd-Warshall算法核心語句for(k=1;k<=n;k++)for(i=1;i<=n;i++)for(j=1;j<=n;j++)if(e[i][j]>e[i][k]+e[k][j] )e[i][j]=e[i][k]+e[k][j];//輸出最終的結(jié)果for(i=1;i<=n;i++){for(j=1;j<=n;j++){printf("%10d",e[i][j]);}printf("\n");}return 0; }

總結(jié)

以上是生活随笔為你收集整理的数据结构--图(Graph)详解(四)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。