經典的最小生成樹例子,Prime算法,具體的步驟及其註釋本人均在代碼中附加,請仔細閱讀與品味,要求,能夠熟練的打出。ios
1 //Prime算法基礎 2 #include<iostream> 3 using namespace std; 4 5 int main() 6 { 7 int n,m,i,j,k,min,t1,t2,t3; 8 int e[7][7],dis[7],book[7] = {0}; 9 int inf = 99999999; 10 int count = 0,sum = 0; 11 cin >> n >> m; 12 13 //初始化 用鄰接矩陣存儲 14 for(int i = 1;i <= n;i++) 15 for(int j = 1;j <= n;j++) 16 if(i == j) 17 e[i][j] = 0; 18 else 19 e[i][j] = inf; 20 21 //讀入邊 無向圖來回都得設置權值 22 for(int i = 1;i <= m;i++) 23 { 24 cin >> t1 >> t2 >> t3; 25 e[t1][t2] = t3; 26 e[t2][t1] = t3; 27 } 28 29 //初始化dis數組,這裏是第一個頂點到各個頂點的初始距離,由於當前生成樹中只有一個頂點 30 for(int i = 1;i <= n;i++) 31 dis[i] = e[1][i]; 32 33 //Prime核心部分 34 //將第一個頂點(即1號頂點)加入生成樹 35 book[1] = 1;//這裏用book數組來標記一個頂點是否已經加入生成樹 36 count++;//表示生成樹中已加入一個頂點 37 while(count < n) 38 { 39 min = inf; 40 41 //掃描找出距離當前根頂點相鏈接的最小權值的頂點 42 for(int i = 1;i <= n;i++) 43 { 44 if(book[i] == 0 && min > dis[i])//若是根節點未被標記而且根節點到剩下的n-1個頂點之間有直連線(就是相連着的邊) 45 { 46 min = dis[i];//就將這條邊的權值代替以前初始化時的無窮大 ,更新min的值,min的值更新只在此for循環中有效,此for循環目的是找出鏈接根節點權值最小的那個頂點j,再把min放入for循環中,一直比較,直至找到最小的權值及連的頂點j 47 j = i;//同時將此時的頂點的編號記錄在臨時變量j中,以便接下來使用 48 } 49 } 50 book[j] = 1;//將上面for循環中找到的最小權值的頂點j加入到生成樹中並標記 51 count++;//生成樹中的頂點加一 52 sum += dis[j];//將權值最小的邊都累加,最終獲得最優解 53 54 //掃描當前頂點j全部的邊,再以j爲中心點,更新生成樹到每個非樹頂點的距離 55 for(k = 1;k <= n;k++) 56 { 57 if(book[k] == 0 && dis[k] > e[j][k])//e[k]表示第一個加入的根頂點到頂點k之間的權值(可能直接鏈接也可能間接鏈接),e[j][k]表示的是當前根頂點做爲j,到與j頂點直接相連的頂點k的權值 58 dis[k] = e[j][k];//此循環的目的是找出離j頂點最近的頂點 59 } 60 } 61 cout << sum; 62 return 0; 63 } 64 /* 65 6 9 66 2 4 11 67 3 5 13 68 4 6 3 69 5 6 4 70 2 3 6 71 4 5 7 72 1 2 1 73 3 4 9 74 1 3 2 75 19 76 */
運行結果:算法
Kruskal算法,須要用到並查集,具體請看如下代碼數組
1 //Kruskal算法 2 #include<iostream> 3 #include<algorithm> 4 using namespace std; 5 struct edge 6 { 7 int u; 8 int v; 9 int w; 10 }e[10];//爲了方便排序,這裏建立了一個結構體數組來存儲邊的關係,數組大小根據實際狀況來設置,要比m的最大值大1 11 int n,m; 12 int f[7],sum = 0,countt = 0;//並查集須要用到的一些變量,f數組大小根據實際狀況來設置,要比n的最大值大1 13 14 ////這個也是快速排序,也能夠替代sort函數 15 //void quicksort(int left,int right) 16 //{ 17 // int i,j; 18 // struct edge t; 19 // if(left > right) 20 // return; 21 // i = left; 22 // j = right; 23 // while(i != j) 24 // { 25 // //順序很重要,要先從右邊開始找 26 // while(e[j].w >= e[left].w && i < j) 27 // j--; 28 // //再從左邊開始找 29 // while(e[i].w <= e[left].w && i < j) 30 // i++; 31 // //交換 32 // if(i < j) 33 // { 34 // t = e[i]; 35 // e[i] = e[j]; 36 // e[j] = t; 37 // } 38 // } 39 // //最終將基準數歸位,將left和i互換 40 // t = e[left]; 41 // e[left] = e[i]; 42 // e[i] = t; 43 // 44 // quicksort(left,i - 1);//繼續處理左邊的,這裏是一個遞歸的過程 45 // quicksort(i + 1,right);//繼續處理右邊的,這裏是一個遞歸的過程 46 // return; 47 //} 48 49 //並查集尋找祖先的函數 50 int getf(int v) 51 { 52 if(f[v] == v) 53 return v; 54 else 55 { 56 //這裏是路徑壓縮 57 f[v] = getf(f[v]); 58 return f[v]; 59 } 60 } 61 //並查集合並兩個子集合的函數 62 int merge(int v,int u) 63 { 64 int t1,t2; 65 t1 = getf(v); 66 t2 = getf(u); 67 if(t1 != t2)//判斷兩個點是否在同一個集合中 68 { 69 f[t2] = t1; 70 return 1; 71 } 72 return 0; 73 } 74 75 bool cmp(const edge &a,const edge &b) 76 { 77 return a.w < b.w; 78 } 79 80 int main() 81 { 82 //讀入頂點個數n和邊的條數m 83 cin >> n >> m; 84 //讀入邊,這裏用結構體數組來存儲邊的關係 85 for(int i = 1;i <= m;i++) 86 cin >> e[i].u >> e[i].v >> e[i].w; 87 // quicksort(1,m);//按照權值從大到小對邊進行快速排序 88 //快速排序權值 89 sort(e + 1,e + m + 1,cmp); 90 //並查集初始化 91 for(int i = 1;i <= n;i++) 92 f[i] = i; 93 94 //Kruskal算法核心部分 95 for(int i = 1;i <= m;i++) 96 { 97 //判斷一條邊的兩個頂點是否已經連通,即判斷是否已在同一個集合中 98 if(merge(e[i].u,e[i].v))//若是目前不連通,則選用這條邊 99 { 100 countt++;//知足條件將頂點加入生成樹 101 sum += e[i].w;//路徑累加和 102 } 103 if(countt == n - 1)//當頂點均加入到生成樹中時,結束循環 104 break; 105 } 106 cout << sum << endl; 107 return 0; 108 }
運行結果:函數
並查集例題ui
下面是對並查集使用的代碼,並查集不太理解的能夠看看下面的代碼spa
1 //並查集的使用 2 #include<iostream> 3 using namespace std; 4 int f[1000],n,m,k,sum; 5 6 //這是找爹的遞歸函數,不停的去找爹,直到找到祖宗爲止,即找到根節點,這個函數的目的是判斷兩個頂點是否屬於同一個集合 7 int getf(int v) 8 { 9 if(f[v] == v) 10 return v; 11 else 12 { 13 /*這裏是路徑壓縮,每次在函數返回的時候,順帶把同一個集合裏面的元素都改成根節點的祖先編號,這樣能夠提升從此找到樹的祖先的速度*/ 14 f[v] = getf(f[v]); 15 return f[v]; 16 } 17 } 18 //這裏是合併兩子集合的函數,在合併函數中調用getf函數,看兩個頂點是不是屬於同一個集合,而後再決定是否執行合併操做 19 void merge(int v,int u) 20 { 21 int t1,t2; 22 t1 = getf(v); 23 t2 = getf(u); 24 if(t1 != t2)//根據調用getf的函數,判斷兩個頂點是否在同一個集合中,便是否爲同一個祖先 25 { 26 f[t2] = t1; 27 } 28 } 29 30 int main() 31 { 32 int x,y; 33 cin >> n >> m; 34 //這裏是初始化,很是的重要,數組裏面存的是本身數組下標的編號就行了 35 for(int i = 1;i <= n;i++) 36 f[i] = i; 37 for(int i = 1;i <= m;i++) 38 { 39 cin >> x >> y; 40 merge(x,y);//將兩個頂點傳入合併集合函數中進行操做 41 } 42 for(int i = 1;i <= n;i++) 43 { 44 if(f[i] == i)//根節點的值依舊是原先的值,即判斷有幾個頂點的值不變即有幾個不一樣的集合 45 sum++; 46 } 47 cout << sum << endl; 48 return 0; 49 } 50 /* 51 10 9 52 1 2 53 3 4 54 5 2 55 4 6 56 2 6 57 8 7 58 9 7 59 1 6 60 2 4 61 3 62 */
運行結果:3d
✌code