破圈法求解最小生成樹c語言實現(已驗證)


破圈法求解最小生成樹c語言實現(已驗證)

下面是算法偽代碼,每一個算法都取一個圖作為輸入,並返回一個邊集T。

對該算法,證明T是一棵最小生成樹,或者證明T不是一棵最小生成樹。此外,對於每個算法,無論它是否能計算出一棵最小生成樹,都要給出其最有效的實現。

MAYBE-MST-A(G,w)

Sort the edges into nonincreasing order of edge weights w

T<-E

For each edge e, taken in nonincreasing order by weight

Do if T-{e} is a connected graph

    Then T<-T-e

Return T

 

 

算法基本思想:

先將圖G的邊按照權的遞減順序排列后,依次檢驗每條邊,在保持連通的情況下,每次刪除最大權邊,直到所有邊都被遍歷到無法刪除任何一邊(或余下n-1條邊為止)。

證明:

生成樹證明:

1、     如果給定連通圖G沒有回路,那么G本身就是一棵生成樹

2、     如果G中只有一個回路,則刪去G的回路上的一條邊(不刪除節點),則產生的圖仍是連通的且沒有回路,則得到的子圖就是G的一棵生成樹;

3、     如果G的回路不止一個,只要刪去每一個回路上的一條邊,知道G的子圖是連通且沒有回路且與圖G有一樣的結點集,那么這個子圖就是一棵生成樹。

4、     重復步驟3,則直到所有邊都不能刪除,由於刪除判斷條件,得到的子圖就是一棵生成樹。

MST證明:

若在某個回路C中有一條唯一的最長邊,則T­­­*中一定不含這條邊,因為優先刪除回路中最長的邊。

若在某個邊e的割集中有一條唯一一條最短邊,則T*中一定含有這條邊(The Cut Property:考慮圖G中的一條邊e。如果存在一個cut(A,B),使得e是所有跨越該割的所有邊中權重最小者,則e一定在G的MST中。

),且不含有其他邊,因為一旦含有其他邊就構成了回路(Lonely-Cut Corollary如果邊e是跨越了cut(A, B)的唯一一條邊,則e不可能在任一圈中。)。

反向證明:假設T*中跨越cut(A,B)的邊不只一條,則在算法結束之前一定會遍歷到其中的成圈的邊(Double-Crossing),根據權值選取方法和刪除圈的一邊仍為連通圖的條件,一定會將權值較大的邊刪除,直到無環且剩下的唯一一條邊是最短邊。

算法變量:

a[n][n]:帶權圖的鄰接矩陣,a[i][j]=w或a[i][j]=0;

max:標記當前找到的准備刪去的邊的權值;

p:標記找到的要刪去的權值所在的行號;

q:標記找到的要刪去的權值所在的列好;

am:標記找到的最大元素(am是為了保護權值大但不能刪的邊),如果a[i][j]不能刪除,則可以讓a[p][q]=am,a[q][p]=am來還原剛才刪去的邊;

I,j:二維數組的行號和列號

sm:圖的邊數,每刪除一個邊,sm就減1,當sm=n-1時,結束

wt:最小生成樹的權值和

算法實現(c語言)

  1 #include<stdio.h>
BY Yuanshuai Zheng,UESTC 2 #define n 5 3 int a[n][n]; 4 int flag,am,p,q; 5 INPUT() 6 { 7 int i,j; 8 printf("輸入圖的帶權鄰接矩陣:\n"); 9 for(i = 0;i<n;i++) 10 { 11 for(j=0;j<n;j++) 12 scanf("%d",&a[i][j]); 13 } 14 } 15 OUTPUT(int a[n][n]) 16 { 17 int i,j; 18 for(i=0;i<n;i++) 19 { 20 for(j=0;j<n;j++) 21 printf("%5d",a[i][j]); 22 printf("\n"); 23 } 24 } 25 MAX(int a1[n][n],int am1,int p1,int q1) 26 { 27 int i,j,ptm,qtm; 28 int max; 29 max = 0; 30 for(i=0;i<n;i++) 31 { 32 for(j=i;j<n;j++) 33 if((a1[i][j]>max)&&(a1[i][j]<=am1)&&((i!=p1)||(j!=q1))) 34 { 35 max = a1[i][j]; 36 ptm = i; 37 qtm = j; 38 39 } 40 } 41 am = max; 42 printf("max=%5d\t",am); 43 p = ptm; 44 q = qtm; 45 a[p][q]=0; 46 a[q][p]=0; 47 } 48 WSHALL(int array[n][n]) 49 { 50 int i,j,k,m=0; 51 int r[n][n],B[n][n]; 52 for(i=0;i<n;i++) 53 { 54 for(j=0;j<n;j++) 55 { 56 r[i][j]=0; 57 B[i][j]=array[i][j]; 58 //分界線 59 if(array[i][j]>=1) 60 B[i][j]=1; 61 else 62 B[i][j]=0; 63 //分界線 64 } 65 } 66 for(j=0;j<n;j++) 67 { 68 for(i=0;i<n;i++) 69 if(B[i][j]>=1) 70 { 71 for(k=0;k<n;k++) 72 { 73 if(B[k][i]>=1) 74 { 75 B[k][j]=B[j][k]=1; 76 } 77 } 78 } 79 } 80 for(i=0;i<n;i++) 81 { 82 for(j=0;j<n;j++) 83 if(!B[i][j]) 84 { 85 return 0; 86 } 87 } 88 return 1; 89 } 90 91 //方法1 92 // for(k=0;k<n;k++) 93 // B[i][j]=B[i][k]+B[j][k]; 94 // } 95 // } 96 // for(i=0;i<n;i++) 97 // { 98 // for(j=0;j<n;j++) 99 // { 100 // r[i][j]=B[i][j]; 101 // { 102 // if((r[i][j]>=1)||(i==j)) 103 // m=m+1; 104 // } 105 // } 106 // } 107 // printf("m=%d\t",m); 108 // if(m==n*n) 109 // flag = 1; 110 // else 111 // flag=0; 112 // return(flag); 113 114 int main() 115 { 116 int i,j,sm,wt=0; 117 am = 10000,p=-1,q=-1,sm=0; 118 INPUT(); 119 for(i=0;i<n;i++) 120 { 121 for(j=i;j<n;j++) 122 { 123 if(a[i][j]>0) 124 sm = sm+1; 125 } 126 } 127 printf("\nsm=%d\n",sm); 128 printf("輸出圖的帶權鄰接矩陣:\n"); 129 OUTPUT(a); 130 printf("\n"); 131 while(sm>n-1) 132 { 133 MAX(a,am,p,q); 134 flag=WSHALL(a);//華沙爾算法判斷是否連通 135 //printf("flag= %d",flag); 136 { 137 if(flag==1) 138 { 139 sm=sm-1; 140 //printf("flag= %d",flag); 141 } 142 else 143 { 144 a[p][q]=am; 145 a[q][p]=am; 146 } 147 } 148 } 149 for(i=0;i<n;i++) 150 for(j=i;j<n;j++) 151 { 152 wt=wt+a[i][j]; 153 } 154 printf("\n\n輸出最小生成樹的帶權鄰接矩陣:\n"); 155 OUTPUT(a); 156 printf("最小生成樹的樹權是: %d\n",wt); 157 } 158

代碼驗證:

例子:

0

6

10

0

0

6

0

3

8

5

10

3

0

6

7

0

8

6

0

0

0

5

7

0

0


免責聲明!

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



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