最小生成樹 , Prime 算法

最小生成樹

Prime算法

題上會先給你說幾個村莊,或者幾個點,然後給你幾句話,這幾句話就是點到點之間的距離,然後你沒有錢,但是你想修路,所以呢,你必須找到一個最省錢的方法,把每個地方給連通起來,就比如下面的題

給你從0到6個島,然後每個島與某個島之間有多長的距離

0—1 距離7            0—3距離5             就這樣,然後如圖所示,你沒有錢,只能把路修到最短才行。

這時候你先找一個點,以他爲起點開始規劃

我們需要先找一個起點比如1然後看下哪條路最短,先修一下發現13最短修下一距離是1

然後把13看作一個看做一個整體找到一個與這個整體最小的邊就是5,然後將013連起來

然後這個找與這個整體相連最短的邊,是65相連

 

繼續按照原理更新,與這個整體相連的最短邊是7,連的是4

 

繼續按照原理更新,與這個整體相連的最短邊是5,連的是2

然後繼續套路更新,找與整體相連的最短邊9,連的是6

恭喜你找到的最短的路徑,這個算法告訴我們沒錢,你就帶學好算法,這樣你才能將成本最低化,

但是如果 你有錢(比如是個官二代,富二代)那就不需要考慮了,路都給修通了,交通更便利,錢流動的更快了。

然後思路我們有了下面我們如何用代碼實現呢?

第一點:因爲是2個島之間的距離所以我們保存時就會使用到鄰接矩陣,把這些點的距離都給存下來,然後就用一個標記標記這個島是否已經是整體內的(也就是他已經被連起來了),然後開始修路的話一般都從第1個島(標號爲0)開始修,因爲循環是從1開始遍歷的,所以我們再用一數組來保存修路的長度。

現在我們從第1個島遍歷,1到1距離是0,然後1到其他島的距離更新一下,找出距離1島最近的島,然後把1島標記一下,把這1和最近的島看作一個整體,都標記,再去找距離整體最近的島,一直找到最後一個島,(這個更新距離,每次都找最短的路連接的島,加入整體後標記),遍歷完結束,輸出最短路程

然後我們一起來看一道題,深入一下Prime

HDU—1233

某省調查鄉村交通狀況,得到的統計表中列出了任意兩村莊間的距離。省政府“暢通工程”的目標是使全省任何兩個村莊間都可以實現公路交通(但不一定有直接的公路相連,只要能間接通過公路可達即可),並要求鋪設的公路總長度爲最小。請計算最小的公路總長度。 

Input

測試輸入包含若干測試用例。每個測試用例的第1行給出村莊數目N ( < 100 );隨後的N(N-1)/2行對應村莊間的距離,每行給出一對正整數,分別是兩個村莊的編號,以及此兩村莊間的距離。爲簡單起見,村莊從1到N編號。 
當N爲0時,輸入結束,該用例不被處理。 

Output

對每個測試用例,在1行裏輸出最小的公路總長度。 

Sample Input

3
1 2 1
1 3 2
2 3 4
4
1 2 1
1 3 4
1 4 1
2 3 3
2 4 2
3 4 5
0

Sample Output

3
5
#include<iostream>
#include<queue>
#include<stdio.h>
#include<cstring>
using namespace std;
const int MAXN=100;
const int INF=0x3f3f3f3f;

int mp[100][100];
int dis[10005];//這個數組存的是 還沒被連通的島 到 整體 的距離 
int vis[100];//這個數組用於標記 已被連通的島 
int n,m;
int x,y,z;
void init(){
	memset(vis,0,sizeof(vis));//島都沒有被標記過 
	memset(dis,INF,sizeof(dis));//先假設沒有連通(距離無窮大) 
	for(int i=1;i<=n;i++)//鄰接矩陣存圖,就是把島與島之間的距離想先都變爲無窮大 
	for(int j=1;j<=n;j++)
	{
		if(i==j) mp[i][j]=0;
		else 
		mp[i][j]=INF;
	}
}
void prime(){
	dis[1]=0;//第一個島到第一個島的距離0(自己距離自己的距離) (找一個起始點) 
	while(1){//開始修路 ,直到無路可修 
		int k=-1,minn=INF; //k的作用是用來找1島到島距離 整體 距離最短的島,minn就是距離整體的距離 
		for(int i=1;i<=n;i++)//從1開始遍歷
		{
			if(dis[i]<minn&&!vis[i])//dis[1]=0//之後的dis就是找距離 整體 最短距離 
			{
				minn=dis[i];//找沒有被連通的島到整體的最小的路 
				k=i;//k就是這個島(距離整體最近) 
			}
		}
		if(k==-1) break;//當你把所有島都連同後,k就就一直是-1;跳出循環 
		vis[k]=1;//標記K遍歷過了 (K島被拉入整體) 
		for(int i=1;i<=n;i++)//遍歷給給K島相連的島 
		{
			if(dis[i]>mp[k][i]&&!vis[i]){//距離小於,之前的距離 
				dis[i]=mp[k][i]; //更新這個島到整體的距離 
			}
		}	//這時的dis[]內存的都是距離整體最小的距離,讓他們加起來就可以了
	}
		int ans=0;
		for(int i=1;i<=n;i++)
		ans+=dis[i];
	cout<<ans<<endl;
	 
}
int main(){
	while(scanf("%d",&n)&&n)
	{
		init();
		m=n*(n-1)/2;
		for(int i=0;i<m;i++)
		{
			cin>>x>>y>>z;
			if(mp[x][y]>z)//存圖,X島到Y的距離存到鄰接矩陣中,只存最小的值 
			{
				mp[x][y]=z;
				mp[y][x]=z;
			}
		}
		prime();//調用prime算法 
	}
}

 

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