普里姆(Prim)算法和克魯斯卡爾(Kruskal)算法

        圖是一種基礎又重要的數據結構,圖的生成樹是圖的一個極小連通子圖。最小生成樹是無向連通網的所有生成樹中邊的權值之和最小的一棵生成樹。求圖的最小生成樹可以牽引出很多經典的題目,例如在N個城市之間建立通訊網絡,問怎樣最省經費(不同城市之間的聯繫網的費用不同,也即是邊上的權值不同)。

求圖的最小生成樹有兩種算法,普里姆(Prim)算法和克魯斯卡爾(Kruskal)算法。下面是我對他們的簡化理解。(只對Kruskal進行了簡單的實現)
     Prim算法的主要思想就是:假設N=(V, {E})是連通網,TE是N上最小生成樹邊集合。
(1) U={u0}(u0屬於V),   TE={ }
(2) 在所有uU,vV-U的邊(u,v)E 中找一條代價最小的邊(u0,v0)併入集合TE, 同時v0併入U,
(3) 如果U≠V,轉(2) (直到U=V爲止)
     最後:TE中必有n-1條邊,則T=(V,{TE})爲N的最    小生成樹。
粗略的看起來似乎乾澀難懂,其實方法不難,就是把頂點分成兩個集合,一個是生成樹頂點集合,一個是其它頂點集合,且求最小生成樹的過程就是從其它頂點集合選取點加入到生成樹頂點的過程。怎麼選取呢,其實方法很簡單,就是從其它頂點集合中選一個可以連接到生成樹頂點且權最小的點,加入到生成樹頂點。下面用圖來說明下:


這就是Prim建立最小生成樹的過程。
爲實現此算法需設置輔助數組closedge ,對當前V-U中每個頂點,記錄從U到V-U的代價最小的邊:
struct{
	VerTexType adjvex; //最小邊在U中的那個頂點
	ArcType lowcost;	    //最小邊上的權值
}closedge[MVNum];



    ②Kruskal算法,我認爲這個可能更簡單,具體的方法也實現起來也容易,先構造一個只含 n 個頂點的子圖 SG,然後從權值最小的邊開始,若它的添加不使SG 中產生迴路,則在 SG 上加上這條邊,如此重複,直至加上 n-1 條邊爲止。還是用圖來說明比較好理解:


下面就來Kruskal來簡單實現以下:


#include<iostream>
using namespace std;

typedef struct
{
	int cost;
	char v1,v2;
}Edge;

char temp[100];
int flag=0;
int check(char k,int m)
{
	int i;
	for(i=0;i<m;i++)
	{
		if(temp[i]==k)
			return 1;
	}
	return 0;
}

int main()
{
	int i,j,n,m;
	Edge edges[100],t;
	
	cout<<"輸入頂點數和邊數:";
	cin>>m>>n;
	cout<<"依次輸入多組v1 v2 cost:"<<endl;
	for(i=0;i<n;i++)
	{
		cin>>edges[i].v1>>edges[i].v2>>edges[i].cost;
	}

	for(i=0;i<n;i++)  
    {  
        for(j=i+1;j<n;j++)  
        {  
            if(edges[i].cost>edges[j].cost)  
            {  
                 t=edges[i];
				 edges[i]=edges[j];
				 edges[j]=t;
            }  
        }  
    }  

	for(i=0;i<n;i++)
	{
		if(check(edges[i].v1,m)==0 || check(edges[i].v2,m)==0)
		{
			cout<<edges[i].v1<<"---"<<edges[i].v2<<" "<<edges[i].cost<<endl;
			if(check(edges[i].v1,m)==0)
			{
				temp[flag]=edges[i].v1;
				flag++;
			}
			if(check(edges[i].v2,m)==0)
			{
				temp[flag]=edges[i].v2;
				flag++;
			}
		}
	}

	return 0;
}




                                                                     謝謝!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章