图论 —— 生成树 —— 最小生成树 —— Prim
【基本思想】
Prim 算法基本思想是藍白點思想,用白點代表已進入最小生成樹的點,藍點代表未進入最小生成樹的點。
每次循環都將一個藍點 u 變為白點,并且此藍點 u 與白點相連的最小邊權 min[u] 還是當前所有藍點中最小的。這相當于每次循環讓一個新的點加入生成樹,讓一條最小邊加入生成樹,n-1 次循環就能生成一棵含有 n 個點的樹,最后得到的一定是最小生成樹。
其時間復雜度為:O(N*N),N 代表點數。
【算法分析】
以下圖為例,藍點和虛線代表未進入最小生成樹的點、邊,白點和實現代表已進入最小生成樹是點、邊。
初始時,所有點都是藍點,min[1]=0,min[2、3、4、5]=INF,權值和 MST=0。
第一次循環找到 min[1]=0 最小的藍點 1。將 1 變為白點,接著枚舉與 1 相連的所有藍點 2、3、4,修改它們與白點相連的最小邊權。故有:min[2]=w[1][2]=2,min[3]=w[1][3]=4,min[4]=w[1][4]=7,MST=0。
第二次循環是找到 min[2] 最小的藍點 2。將?2 變為白點,接著枚舉與 2 相連的所有藍點 3、5,修改它們與白點相連的最小邊權。故有:min[3]=w[2][3]=1,min[5]=w[2][5]=2,MST=2。
第三次循環是找到 min[3] 最小的藍點 3。將 3 變為藍點,接著枚舉與 3 相鄰的所有藍點 4、5,修改它們與白點相連的最小邊權。故有:min[4]=w[3][4]=1,由于 min[5]=2<w[3][5]=6,所以不修改 min[5] 的值,MST=3。
最后兩輪循環將點 4、5 以及邊 w[2][5]、w[3][4] 添加進最小生成樹。
最后權值之和 MST=6。
【算法描述】
以 1 為起點生成最小生成樹,vis[v] 代表 v 點是否加入最小生成樹中,min[v] 代表藍點 v 與白點相連的最小邊權,MST 代表最小生成樹邊權之和。
初始化:
vis[1...n]=false,MST=0
min[v]=INF(v≠1),min[1]=0
主體
void Prim() {for(int i=1;i<=n;i++){int u=0;for(int j=1;j<=n;j++)//枚舉所有點if( vis[j]==false && min[j]<min[u])//尋找與白點相連的權值最小的藍點uu=j;vis[u]=true;//藍點u加入生成樹,標記為白點for(int j=1;j<=n;j++)//修改所有與u相連的藍點if( vis[j]==false && g[u][j]<min[j] )min[j]=g[u][j];}//權值和的計算int MST=0;for(int i=1;i<=n;i++)MST+=min[i]; }【模版】
int n,m;//n個點m條邊 int G[N][N]; int dis[N]; bool vis[N]; int MST; void Prim(){for(int i=1;i<=n;i++){int k;int minn=INF;for(int j=1;j<=n;j++){//枚舉所有點if(!vis[j]&&dis[j]<minn){//尋找與白點相連的權值最小的藍點uminn=dis[j];k=j;}}vis[k]=true;//藍點u加入生成樹,標記為白點for(int j=1;j<=n;j++)//修改所有與u相連的藍點if(!vis[j]&&dis[j]>G[k][j])dis[j]=G[k][j];}MST=0;for(int i=1;i<=n;i++)//權值和的計算MST+=dis[i]; }int main(){cin>>n>>m;memset(vis,false,sizeof(vis));for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)cin>>G[i][j];for(int i=1;i<=n;i++)dis[i]=G[1][i];Prim();cout<<MST<<endl;return 0; }總結
以上是生活随笔為你收集整理的图论 —— 生成树 —— 最小生成树 —— Prim的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Bear in the Field(CF
- 下一篇: 最小生成树计数(洛谷-P4208)