普利姆最小生成樹算法
普里姆算法(Prim算法),圖論中的一種算法,可在加權連通圖裏搜索最小生成樹。意即由此算法搜索到的邊子集所構成的樹中,不但包括了連通圖裏的所有頂點(英語:Vertex
(graph theory)),且其所有邊的權值之和亦爲最小。
初始狀態:V是所有頂點的集合,即V={A,B,C,D,E,F,G};U和T都是空!
第1步:將頂點A加入到U中。
此時,U={A}。
第2步:將頂點B加入到U中。
上一步操作之後,U={A}, V-U={B,C,D,E,F,G};因此,邊(A,B)的權值最小。將頂點B添加到U中;此時,U={A,B}。
第3步:將頂點F加入到U中。
上一步操作之後,U={A,B}, V-U={C,D,E,F,G};因此,邊(B,F)的權值最小。將頂點F添加到U中;此時,U={A,B,F}。
第4步:將頂點E加入到U中。
上一步操作之後,U={A,B,F}, V-U={C,D,E,G};因此,邊(F,E)的權值最小。將頂點E添加到U中;此時,U={A,B,F,E}。
第5步:將頂點D加入到U中。
上一步操作之後,U={A,B,F,E}, V-U={C,D,G};因此,邊(E,D)的權值最小。將頂點D添加到U中;此時,U={A,B,F,E,D}。
第6步:將頂點C加入到U中。
上一步操作之後,U={A,B,F,E,D}, V-U={C,G};因此,邊(D,C)的權值最小。將頂點C添加到U中;此時,U={A,B,F,E,D,C}。
第7步:將頂點G加入到U中。
上一步操作之後,U={A,B,F,E,D,C}, V-U={G};因此,邊(E,G)的權值最小。將頂點G添加到U中;此時,U=V。
此時,最小生成樹構造完成!它包括的頂點依次是:A B F E D C G。
1、直接就是進行上面的操作過程;
#include <iostream>
#include <cstring>
#define INF 1<<3
#define NUM 100
using namespace std;
int dot_num;//表示頂點數;
int dot_lines;//表示邊數;
int Graph[NUM][NUM];//存放邊的權值(數組法)
bool visted[NUM] ={false};
struct VNode{
int adjvex;
int lowcost;
}minside[NUM];//存放adjvex這個樹內和樹外連接頂點之間的最小的所有權值;
int min_xu()
{
int i = 1;
int k;
while(!minside[i].lowcost&&i<=dot_num)
i++;//找出第一個非零的值
k = i;//獲取這個的位置
int min_value = minside[i].lowcost;//令這個位置的這個非零值爲最小的值;
for(int j = i;j<=dot_num;j++)
if(min_value>minside[j].lowcost&& minside[j].lowcost>0)
{min_value = minside[j].lowcost;k = j;}//獲取最小的值;
return k;
}
void MiniSpanTree(int v)
{
int k;
for(int i = 1;i<=dot_num;i++){
minside[i].adjvex = v+1;
minside[i].lowcost = Graph[v+1][i];
}
minside[v+1].lowcost = 0;
for(int i = 2;i<=dot_num;i++){
k = min_xu();
cout <<minside[k].adjvex<<"V->V"<<k<<endl;
minside[k].lowcost = 0;
for(int i = 1;i<=dot_num;i++)
if(minside[i].lowcost>Graph[k][i]){//更新在樹外到樹內的所有的權值;
minside[i].adjvex = k;
minside[i].lowcost = Graph[k][i];
}
}
}
int main()
{
cin>>dot_num>>dot_lines;
memset(Graph, 127, sizeof(Graph));
for(int i = 0;i<dot_lines;i++){
int temp1,temp2,value;
cin>>temp1>>temp2>>value;
Graph[temp2][temp1]=value;
Graph[temp1][temp2]=value;
}
MiniSpanTree(0);
return 0;
}
克魯斯卡爾算法
//克魯斯卡爾算法求無向連通網的最小生成樹的程序
#include <iostream>
#include <cstring>
#define NUM 100
#define INF 1<<3
#define MAX_VERTEX_NUM 100
using namespace std;
int dot_num;//表示頂點數;
int dot_lines;//表示邊數;
int G[NUM][NUM];//存放邊的權值(數組法)
bool visted[NUM] ={false};
struct VNode{
int adjvex;
int lowcost;
}minside[NUM];//存放adjvex這個樹內和樹外連接頂點之間的最小的所有權值;
void Kruskal()
{
int set[MAX_VERTEX_NUM];
for(int i=1; i<=dot_num; i++)
set[i]=i;//初始化;//相當於存放每一個頂點;
printf("最小代價生成樹的各條邊爲\n");
int k=0;
int a = 1;
int b = 1;
int min = 1<<30;//表示最小的權值;
while(k<dot_num-1){//表示找出這個n-1條邊
for(int i = 1;i<=dot_num;i++)
for(int j = i;j<=dot_num;j++){
if(G[i][j]<min){
min = G[i][j];
a = i;
b = j;
}
}//找到最小的權值;在所有的邊中。並且記錄其中的頂點是那兩個;
min = G[a][b] = 1<<30;//更該其中的圖的邊的值,並且將這個值賦值給min
if(set[a] !=set[b]){
cout <<a<<"V->V"<<b<<endl;
k++;
int temp = set[b];
for(int i = 1;i<=dot_num;i++)
if(set[i] == temp)
set[i] = set[a];
}
}
}
int main()
{
cin>>dot_num>>dot_lines;
memset(G, 127, sizeof(G));
for(int i = 0;i<dot_lines;i++){
int temp1,temp2,value;
cin>>temp1>>temp2>>value;
G[temp2][temp1]=value;
G[temp1][temp2]=value;
}
Kruskal();
}
測試數據:
6 10
1 2 6
1 3 1
1 4 5
2 3 5
2 5 3
3 4 5
3 5 6
3 6 4
4 6 2
5 6 6