最小生成樹的兩種最基本的演算法
阿新 • • 發佈:2019-01-23
prim
/** @Cain*/
#include <bits/stdc++.h>
using namespace std;
const int maxn=2005;
const int inf=1e9+5;
int edge[maxn][maxn];
int near[maxn];
int low[maxn];
int p,l,n;
void prim()
{
memset(low,0,sizeof(low));
int sum=0;
for(int i=0;i<n;i++)
near[i]=edge[0][i];
low[0]=1;//先定好以哪個點開始建樹,這裡是以0 開始的,若以其他點則相應的位置就可以了.
for(int i=0;i<n-1;i++){
int minn=inf;
int v=-1;
for(int j=0;j<n;j++){
if(!low[j] && near[j]<minn){
minn=near[j];
v=j;
}
}
if(v!=-1){
sum+=minn;
low[v]=1 ;
for(int j=0;j<n;j++){
if(!low[j] && edge[v][j]<near[j])
near[j]=edge[v][j];
}
}
}
cout << sum << endl;
}
int main()
{
cin >> n; //因為輸入是一個矩陣.
/*for(int i=0;i<n;i++){ //無向圖;有向圖把存臨接矩陣那改一下就可以了.
int u,v,w;
scanf("%d %d %d",&u,&v,&w);
edge[u-1][v-1]=edge[v-1][u-1]=w;
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(i==j)
edge[i][j]=0;
else if(edge[i][j]==0)
edge[i][j]=inf;
}
}//這個是輸入為點-點-邊的存法.*/
for(int i=0;i<n;i++){//無向圖;有向圖把存臨接矩陣那改一下就可以了.
for(int j=0;j<n;j++){
scanf("%d",&edge[i][j]);
}
}//這個是輸入為矩陣的存法.
/*for(int i=0;i<n;i++){//列印鄰接矩陣.
for(int j=0;j<n;j++){
printf("%d ",edge[i][j]);
}
printf("\n");
}*/
prim();//所以prim即適用於矩陣輸入,也適用於邊輸入.只是邊輸入時用kruskal更簡單.
}
/*
3
0 1 2
1 0 3
2 3 0//這個是矩陣的存法.
3
1 2 1
1 3 2
2 3 3//這個是kruskal的存法.
*/
kruskal
//這個是有兩種寫法,如果單獨算最小生成樹,則節點 最好選其 本身 ,如果加上判環那些則節點最好選為-1,在此都貼下 相應程式碼.
節點為本身的
/** @Cain*/
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int n,m;
int pre[maxn];
struct node
{
int u,v,w;
node(int u=0,int v=0,int w=0):u(u),v(v),w(w){};
bool operator < (const node &a) const {
return a.w>w;
}
}s[maxn];
int Find(int x)
{
return pre[x]==x?x:pre[x]=Find(pre[x]);
}
void solve()
{
while(~scanf("%d",&n)){
if(!n) break;
scanf("%d",&m);
for(int i=0;i<m;i++){
scanf("%d%d%d",&s[i].u,&s[i].v,&s[i].w);
}
for(int i=0;i<=n;i++) pre[i] = i;
sort(s,s+m);
int ans = 0,num=0;
for(int i=0;i<m;i++){
int u = Find(s[i].u),v = Find(s[i].v);
if(u != v){
pre[u] = v;
ans += s[i].w;
num++;
}
if(num == n-1) break;
}
printf("%d\n",ans);
}
}
//有時候節點為-1時題目的要求會好實現的多! 所以還是要學到!!! 至少要記得有這種方式 !!!
節點為-1的.
/** @Cain*/
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5;
int n,m;
int fa[maxn];
struct node
{
int u,v,w;
node(int u=0,int v=0,int w=0):u(u),v(v),w(w){};
bool operator < (const node &a) const {
return a.w>w;
}
}s[maxn];
int Find(int x)
{
return fa[x]<0?x:fa[x]=Find(fa[x]);
}
void Union(int x,int y)
{ int m=Find(x);
int n=Find(y);
int tmp=fa[m]+fa[n];
if(fa[m]>fa[n]){//總是讓節點少的加到節點大的那棵樹上去.
fa[m]=n;
fa[n]=tmp;
}
else{
fa[n]=m;
fa[m]=tmp;
}
}
void kruskal()
{
int ans=0;//儲存總長度.
int sum=0;//已用邊條數
memset(fa,-1,sizeof(fa));
for(int i=0;i<m;i++){
int u=s[i].u,v=s[i].v;
if(Find(u)!=Find(v))
{
ans+=s[i].w;
sum++;
Union(u,v);
}
if(sum>=n-1) break;;
}
printf("ans = %d\n",ans);
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=0;i<m;i++){
scanf("%d %d %d",&s[i].u,&s[i].v,&s[i].w);
}
sort(s,s+m);
kruskal();
}