---
tags: 演算法
title: Prim`s 演算法
---
## Prim`s 演算法
### 解決 最小生成樹(MST) 問題
> 在 **"稠密圖"** 時表現較佳
### 核心思想
> 貪心思想
> -> 選定任意一個起點開始拓展
> -> 每次都選距離現在這棵樹最短的那條邊
> -> 做完後 連起來的就會是 最小花費
> 跟 Dijkstra 很像 幾乎一樣
>
> Dijkstra -> **從找到最小花費那個點出發** 找距離最近的點 拓展
> Prim`s -> **從當前的生成樹出發** 找距離 **樹** 最近的點 拓展
### 優化
> 和 dijkstra 一樣 時間複雜度主要來自 **"提取最小值"**
> 因此一樣可以使用 priority_queue 做優化
### 實作技巧
> 一般版:
> 用 set 存已訪問過的點比較方便 -> 因為每次都要走訪集合裡所有的點
```CPP
set<int> cs;
int e_count = 0 ,cost = 0; //加入邊數和總花費
cs.insert(1);
while(e_count != V-1 ){
int min_cost = inf, min_point = -1;
for(int i:cs)
for(auto j:gp[i])
if(!cs.count(j.first)&&j.second<min_cost){
min_cost = j.second;
min_point = j.first;
}
if(min_point != -1){
cost += min_cost;
cs.insert(min_point);
e_count++;
}
}
```
> priority_queue 版:
```CPP
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> prim;
vector<bool> cs(V+1,false);
int e_count = 0, cost=0;
prim.push({0,1});
while (e_count != V ) { //第一次沒有加上邊只是初始化 所以是到 V
auto t = prim.top();
prim.pop();
if (cs[t.second])
continue;
cost += t.first;
cs[t.second] = true;
for (auto j : gp[t.second])
if(!cs[j.first])
prim.push({j.second,j.first});
e_count++;
}
```
#### 坑
- 請記得這會是一個 "無向圖" 所以插入邊的時候兩個點都要插 謝謝 !
### 相關題目
UVa 908:
```cpp=
#include "bits/stdc++.h"
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
int main(){
int V;
bool f = 1;
while(cin>>V){
//init and input
if (!f)
cout << endl;
f = false;
vector<vector<pair<int, int>>> gp(V+1);
int oldcost = 0;
for(int i=1;i<V;i++){
int s,e,w; cin>>s>>e>>w;
oldcost += w;
}
int add; cin >> add;
while(add--){
int s, e, w;
cin >> s>>e>> w;
gp[s].push_back({e,w});
gp[e].push_back({s, w});
}
cin >> add;
while (add--) {
int s, e, w;
cin >> s>>e>> w;
gp[s].push_back({e,w});
gp[e].push_back({s, w});
}
//prim`s algorithm
set<int> cs;
int e_count = 0 ,cost = 0;
cs.insert(1);
while(e_count != V-1){
int min_cost = inf, min_point = -1;
for(int i:cs)
for(auto j:gp[i])
if(!cs.count(j.first)&&j.second<min_cost){
min_cost = j.second;
min_point = j.first;
}
if(min_point != -1){
cost += min_cost;
cs.insert(min_point);
e_count++;
}
}
//output
cout<<oldcost<<endl<<cost<<endl;
}
return 0;
}
```