1、問題引入
一個有n個頂點的有向圖的傳遞閉包為:有向圖中的初始路徑可達情況可以參見其鄰接矩陣A,鄰接矩陣中A[i,j]表示i到j是否直接可達,若直接可達,則A[i,j]記為1,否則記為0;兩個有向圖中i到j有路徑表示從i點開始經過其他點(或者不經過其他點)能夠到達j點,如果i到j有路徑,則將T[i,j]設置為1,否則設置為0;有向圖的傳遞閉包表示從鄰接矩陣A出發,求的所有節點間的路徑可達情況,該矩陣就為所要求的傳遞閉包矩陣。。。
例如:
有向圖為:
由該有向圖可以得到初始的鄰接矩陣為:
那么warshall傳遞閉包算法的目的就是由鄰接矩陣出發,進行探索求出最終的傳遞閉包:
2、動態規划求解思路
動態規划將問題分段,本例warshall算法是通過一系列n階矩陣r(k)來構造最終階段n階傳遞閉包矩陣r(n)
R(k) 由它的前趨 R(k-1) 計算得到(分級推進計算)。
R(0) ——該矩陣不允許它的路徑中包含任何中間頂點,即從該矩陣的任意頂點出發的路徑不含有中間頂點,此即鄰接矩陣。
R(1) ——允許路徑中包含第1個頂點(本例編號 1)作為中間頂點。
R(2) ——允許路徑中包含前2個頂點(本例編號1 2)作為中間頂點。
R(k) ——允許路徑中包含前k個頂點作為中間頂點。
R(n) ——允許路徑中包含全部 n 個頂點作為中間頂點。
每個后繼矩陣 R(k) 對其前趨 R(k-1) 來說,在路徑上允許增加一個頂點, 因此有可能包含更多的1(增加前為1的在增加后依然為1)。
3、具體的算法描述
1 warshall(A[1...n,1...n] 2 r(0)<-A; 3 for(k=1;k<=n;k++) 4 for(i=1;i<=n;i++) 5 for(j=1;j<=n;j++) 6 r(k)[i,j]=r(k-1)[i,j] or(r(k-1)[i,k] and r(k-1)[k,j]); 7 return r(n);
4、具體實現代碼如下
說明:(1)有向圖的頂點個數和初始鄰接矩陣存儲在2.txt中(具體如下圖),其中4表示有向圖中有4 個頂點,其他表示初始鄰接矩陣。
(2)有向圖的頂點個數和初始鄰接矩陣個數可以隨意更改,,,,
具體代碼:
1 #include<stdio.h> 2 #include<stdlib.h> 3 void Warshall(int,int**); 4 void main() 5 { 6 int i,j,num; 7 FILE*p; 8 p=fopen("2.txt","r"); 9 if(p==NULL) 10 { 11 printf("cannot open 2.txt"); 12 exit(-1); 13 } 14 fscanf(p,"%d",&num); 15 int **r=(int**)malloc(sizeof(int*)*(num+1)); 16 for(i=0;i<num+1;i++) 17 r[i]=(int*)malloc(sizeof(int)*(num+1)); 18 for(i=1;i<num+1;i++) 19 for(j=1;j<num+1;j++) 20 fscanf(p,"%d",&r[i][j]); 21 printf("頂點個數為:%d\n",num); 22 printf("鄰接矩陣為:\n"); 23 for(i=1;i<num+1;i++) 24 { 25 for(j=1;j<num+1;j++) 26 printf(" %d ",r[i][j]); 27 printf("\n"); 28 } 29 Warshall(num,r); 30 printf("最終的傳遞閉包為\n"); 31 for(i=1;i<num+1;i++) 32 { 33 for(j=1;j<num+1;j++) 34 printf(" %d ",r[i][j]); 35 printf("\n"); 36 } 37 38 } 39 //三重循環實現的warshall算法 40 //r為鄰接矩陣,中間存儲初試的可達與非可達路徑情況,1表示可達,0表示不可達 41 void Warshall(int num,int**r) 42 { 43 int i,j,k; 44 int **temp=(int**)malloc(sizeof(int*)*(num+1)); 45 for(i=0;i<num+1;i++) 46 temp[i]=(int*)malloc(sizeof(int)*(num+1)); 47 for(k=1;k<=num;k++)//依次取得的可以作為中間點的頂點 48 { 49 for(i=1;i<=num;i++) 50 { 51 for(j=1;j<=num;j++) 52 { 53 temp[i][j]=(r[i][j])||(r[i][k]&r[k][j]); 54 } 55 } 56 for(i=1;i<=num;i++) 57 for(j=1;j<=num;j++) 58 r[i][j]=temp[i][j]; 59 } 60 61 }
5、結果如下:
6、參考文獻
(1)算法導論
(2)數據結構 嚴蔚敏
(3)網上下載的ppt(第8章 動態規划)