Warshall傳遞閉包算法的學習與實現


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章 動態規划)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM