最小生成樹
Prime算法
題上會先給你說幾個村莊,或者幾個點,然後給你幾句話,這幾句話就是點到點之間的距離,然後你沒有錢,但是你想修路,所以呢,你必須找到一個最省錢的方法,把每個地方給連通起來,就比如下面的題
給你從0到6個島,然後每個島與某個島之間有多長的距離
0—1 距離7 0—3距離5 就這樣,然後如圖所示,你沒有錢,只能把路修到最短才行。
這時候你先找一個點,以他爲起點開始規劃
我們需要先找一個起點比如1然後看下哪條路最短,先修一下發現1到3最短修下一距離是1
然後把1和3看作一個看做一個整體找到一個與這個整體最小的邊就是5,然後將0和1和3連起來
然後這個找與這個整體相連最短的邊,是6與5相連
繼續按照原理更新,與這個整體相連的最短邊是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算法
}
}