最小生成树有两种算法,一种是克鲁斯卡尔(Kruskal)算法。
这种算法只与边相关,所以在定义数组的时候定义一个结构体
struct list
{
int x;//边的一个点
int y;//边的另一个点
int l;//边的权值
}s[500];//存储边
1.先对所有的边按照权值排序。
2.找到最小的那个边,查看边的两点是不是都找到了,如果不是,继续下一步。
『
对于这个地方,需要使用到并查集,把所有的已经找到的点放在一个并查集里面,然后直接判断这个边的两个点的值是不是一样就可以了。
int get(int x)
{
while(f[x]!=x)
x=f[x];
return x;
}
int find(int x,int y)
{
x=get(x);
y=get(y);
if(x==y)return 0;
f[y]=x;
return 1;
}
3.继续第二步,直到找到最小生成树。
hdu 1233
#include<stdio.h>
#include<stdlib.h>
struct list
{
int x,y;
int l;
}s[10000];
int f[1002];
int cmp(const void *a,const void *b)
{
return (*(struct list *)a).l>(*(struct list *)b).l?1:-1;
}
int get(int x)
{
while(f[x]!=x)
x=f[x];
return x;
}
int find(int x,int y)
{
x=get(x);
y=get(y);
if(x==y)return 0;
f[y]=x;
return 1;
}
int main()
{
int n,i,m;
while(scanf("%d",&n)&&n)
{
for(i=1;i<=n;i++)
f[i]=i;
m=n*(n-1)/2;
for(i=0;i<m;i++)
{
scanf("%d%d%d",&s[i].x,&s[i].y,&s[i].l);
}
qsort(s,m,sizeof(s[0]),cmp);
long long sum=0;
int leap=1;
for(i=0;i<m;i++)
{
if(find(s[i].x,s[i].y))
{
sum+=s[i].l;leap++;
if(leap==n)break;
}
}
printf("%lld\n",sum);
}
return 0;
}
二:普利姆(Prime)算法
这个算法主要是与点有关系。所以定义数组的时候定义map[][];
算法过程:
1.先随便选一个点i,定义一个low数组,存储点i到其它点的距离。定义一个visit数组,判断是否被访问过。
2.寻找low数组中的最小数,然后搜寻一遍这个数到其他点的距离是不是小于low数组,如果小于,就更新low数组。
3.循环2步骤,直至找到最小数。
hdu 1233
#include<stdio.h>
#include<string.h>
#define INF 0x3f3f3f3f
int main()
{
int n,a,b,c;
int map[102][102];
while(scanf("%d",&n)&&n)
{
int m,i;
m=n*(n-1)/2;
memset(map,0,sizeof(map));
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
map[a][b]=c;
map[b][a]=c;
}
int visit[102],low[102],min,leap,j;
memset(visit,0,sizeof(visit));
visit[1]=1;
for(i=1;i<=n;i++)
low[i]=map[1][i];
int sum=0;
for(i=1;i<=n;i++)
{
min=INF;
for(j=1;j<=n;j++)
{
if(visit[j]==0&&min>low[j])
{
min=low[j];leap=j;
}
}
if(min==INF)break;
sum+=min;
visit[leap]=1;
for(j=1;j<=n;j++)
{
if(low[j]>map[leap][j])
low[j]=map[leap][j];
}
}
printf("%d\n",sum);
}
return 0;
}