最小生成树是一副连通加权无向图中一棵权值最小的生成树。
解决最小生成树一般有两种算法,克鲁斯卡尔算法(Kruskal Algorithm)和普利姆算法(Prim Algorithm)。
克鲁斯卡尔算法的核心就在带权连通图中,不断地在边集合中找到最小的边,如果该边满足得到最小生成树的条件,就将其构造,直到最后得到一颗最小生成树。用并查集来判断当前路径是否出现过。
普利姆算法的核心步骤是在带权连通图中,从图中某一顶点v开始,此时集合U={v},重复执行下述操作:在所有u∈U,w∈V-U的边(u,w)∈E中找到一条权值最小的边,将(u,w)这条边加入到已找到边的集合,并且将点w加入到集合U中,当U=V时,就找到了这颗最小生成树。
int prime(int cur)//Prim
{
int index;
int sum = 0;
memset(visit, false, sizeof(visit));
visit[cur] = true;
for(int i = 0; i < m; i ++){
dist[i] = graph[cur][i];
}
for(int i = 1; i < m; i ++){
int mincost = INF;
for(int j = 0; j < m; j ++){
if(!visit[j] && dist[j] < mincost){
mincost = dist[j];
index = j;
}
}
visit[index] = true;
sum += mincost;
for(int j = 0; j < m; j ++){
if(!visit[j] && dist[j] > graph[index][j]){
dist[j] = graph[index][j];
}
}
}
return sum;
}
最小生成树模板题:https://vjudge.net/problem/14339/origin
克鲁斯卡尔算法
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
int a[30];
struct node
{
int x,y,t;
}map[100];
bool cmp(node a,node b)
{
return a.t<b.t;
}
int find(int p)
{
if(a[p]==p)
return a[p];
else
{
a[p]=find(a[p]);
return a[p];
}
}
void add(int q,int w)
{
int t1,t2;
t1=find(q);
t2=find(w);
a[t1]=t2;
return;
}
int main ()
{
int n;
while(cin>>n)
{
if(n==0)
break;
int num=0;
for(int i=0;i<30;i++)
{
a[i]=i;
}
int k=0;
for(int i=0;i<n-1;i++)
{
int m;
char s1;
cin>>s1>>m;
for(int j=0;j<m;j++)
{
char s2;
int l;
cin>>s2>>l;
map[k].x=s1-'A';
map[k].y=s2-'A';
map[k].t=l;
k++;
}
}
sort(map,map+k,cmp);
int cnt=0;
for(int i=0;i<k;i++)
{
int t1,t2;
t1=find(map[i].x);
t2=find(map[i].y);
if(t1==t2)
continue;
else
{
add(map[i].x,map[i].y);
num+=map[i].t;
cnt++;
}
if(cnt==n-1)
{
cout<<num<<endl;
break;
}
}
}
}