之前學的時候一直感覺是兩個演算法沒什麼區別,今天總結一下:
大體思路:
prim演算法是做n次確定每乙個點,使其構成最小生成樹。
而相對比的是krusckal演算法是做n-1次,找到n-1條最短邊,以此來確定n個點。
假設給定n個點,以及m條邊,既然是無向的,且有可能使其連通,那麼邊數m必定是 n-1<= m <=n*(n-1)/2。
下面給出**和具體差別的思路想法:
1.prim演算法(確定點)
演算法的思想:
標記當前點(思路二的實現,思路乙隻是第一次空跑)
步驟: 取第乙個點,進行向外找到當前這乙個點可以到達的最短的邊,sum+=邊長,標記當前找到的點,防止以後再次訪問該點。
在當前已經拿到的兩個點,找下乙個使用最小的權值可以到達的另外乙個沒標記過的點。
在當前已經拿到的三個點,找。。。。。。。。。。。。。。。。。。。。。。。。。。
依次類推。到最後我們拿到了n個點,也就是n-1條邊,這就是最小的生成樹,即最小的權值和。
看了下網上各位的思路有兩種:
第一種是迴圈n次,
這個n分為了
其中第一步是確定了當前使用的點,是空跑,當前權值並不發生改變。先給出第一種的**:
#include #include #define inf 99999999
using namespace std;
int n,m;
int mp[1005][1005];
int vis[1005];
int dis[1005];
void prim(int cur)
int index=cur;
int minn=inf;
for(int k=1;k<=n;k++)
prim(1);
return 0;
}
再給出第二種**:
是n-1次迴圈,因為在初始時已經確立了x點(比如vis[1])為起始點,進行多次尋找。
#include #include #define inf 99999999
using namespace std;
int n,m;
int mp[1005][1005];
int vis[1005];
int dis[1005];
void prim(int cur)
int index=cur;
int minn=inf;
vis[1]=1;//區別在這裡和下一行。
for(int k=1;k<=n-1;k++)//
prim(1);
return 0;
}
2.kruskal演算法
感覺還是很好理解的,看了別人的思路,可以自己手敲一遍,自己都可以按照學過的知識敲出來。
演算法思路:
n個點可以由n-1條邊連通,在不新增多餘邊的情況下,我們自然要找到這n-1條邊是哪些邊。
首先我們將這n個頂點看成n棵孤立的樹,接下來的操作是每一條邊將st ed兩個頂點連線。
當然如果這兩個頂點已經在同一棵樹上了,那麼我們這條邊加上後就一定會形成乙個圈,就浪費了這個權值,所以只有當兩個點不在一棵樹上的時候我們才進行連線。
那麼上述操作就是乙個並查集合並根節點的操作。
而這些邊的選取規則是從小到大依次選取,只要這條邊加入後不會形成圈(也就是邊的兩個點原來不在同一棵樹上)。
我們可以記錄一下我們已經加入了多少條邊,當邊數==n-1時候退出。
#include #include #include using namespace std;
int father[50005];
struct node
edge[50005];
int vis[50005];
int n,m;
int sum=0,temp=0;
int cmp(node x,node y)
sort(edge+1,edge+1+m,cmp);
kruskal();
return 0;
}
最小生成樹 Prim
include stdio.h include stdlib.h include io.h include math.h include time.h define ok 1 define error 0 define true 1 define false 0 define maxedge 20 ...
最小生成樹 prim
演算法模型 由任意乙個頂點開始 將此頂點存入s集,剩餘頂點存入t集合 每次遍歷頂點,取一條能夠連線s與t最短邊e,直到所有頂點全部加入s include include define inf 1 30 int n,m,vis 110 low 110 int map 110 110 int init ...
最小生成樹 PRIM
這個是有關普利姆的演算法,從乙個點出發,找出與這個點相連的所有點的對應的權值最小的那個,然後再把這個點從集合中劃掉。模板如下 include include define inf 0xfffff define max 2005 using namespace std int map max max ...