最近刚学了最小生成树的Kruskal算法,调试了好久,终于过了,比较浪费时间和空间,就是按照原本的思路写的,以后学着优化,把边排序。这次是用邻接矩阵实现的,以后试着用邻接表实现。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int Map[501][501];
int Father[501];
bool Vis[501][501];
int find(int x) //find 操作
{
if( Father[x]==x ) return x;
else return Father[x]=find(Father[x]);
}
int unin(int a,int b) //合并操作
{
int u1=find(a);
int u2=find(b);
if( u1!=u2 )
Father[u2]=u1;
}
void Init(int a) //Father数组初始化
{
for(int i=1;i<=a;i++)
Father[i]=i;
}
int Kruskal( int Vertex )
{
for( int i=1;i<=Vertex;i++ ) //将没有连接的边初始化为无穷大
for( int j=1;j<i;j++ )
if( !Map[i][j] )
Map[i][j]=10000000;
int sum=0;
for( int h=1;h<Vertex;h++ ) //循环 Vertex - 1 遍,查找 Vertex - 1 条边
{
int Min=1000000;
int o,p;
for( int i=1;i<=Vertex;i++ )//找到没有访问过并且权值最小的边
for( int j=1;j<i;j++ )
{
if( !Vis[ i ][ j ]&&Min>Map[ i ][ j ] )
{
int u1=find( i );
int u2=find( j );
if( u1!=u2 )//查看这两条边是否在同一个集合中
{
Min=Map[ i ][ j ];
o=i;
p=j;
}
}
}
sum+=Min;
unin( o,p ); //连接这两条顶点
Vis[ o ][ p ]=true;//将这条边声明为访问过
}
return sum;
}
int Min( int Vertex )
{
int Min=1000000;
for(int i=0;i<Vertex;i++)
{
int d;
scanf("%d",&d);
if(Min>d)
Min=d;
}
return Min;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset( Map,0,sizeof(Map) );
memset( Vis,false,sizeof(Vis) );
int Vertex,Edge;
scanf("%d%d",&Vertex,&Edge);
Init(Vertex);
for(int i=0; i<Edge; i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
Map[ a ][ b ]=Map[ b ][ a ]=c;
}
printf("%d\n",Kruskal( Vertex )+Min( Vertex ));
}
return 0;
}