求图的最小生成树(prim算法

时间:2021-06-03 12:34:17
//核心 Prim算法求最小生成树
/*
   编一C程序,它能根据输入数据构造带权无向图G,
   并输出G的最小生成树。
    图的输入形式为n  V0 Vi0 w0   V1 Vi1 w1   V2 Vi2 w2   ...Vi Vin wn  -1 -1 -1(-1,-1,-1为输入结束标记,其余的值都>=0且<n),它们都是整数,且100>n>0。


*/
#include <stdio.h>

#define infinity 1000000  //常数infinity为无穷大
#define max_vertexes 100    //常数max_vertexes为图最大节点数


void prim(int G[][max_vertexes],int vcount,int father[]);
int juZhen(int g[][max_vertexes]);

void main()
{
    int g[max_vertexes][max_vertexes];
	int vcount=0,father[max_vertexes];        
    vcount=juZhen(g); //初始化矩阵
	printf("该图的最小生成树为\n");
    prim(g,vcount,father);  
}

/*
  lowcost: 记录权值的
  used[]:   //记录每个顶点是否被并入:默认值为0;当并入后修改对应值为1

  father[]:
  closeset[]:  
*/

void prim(int G[][max_vertexes],int vcount,int father[])   
{
    int i,j,k,m=0;
    int lowcost[max_vertexes],closeset[max_vertexes],used[max_vertexes];

	int min;

    //初始化------------------------------------
    for (i=0;i<vcount;i++)     
    {  
		used[i]=0;
		closeset[i]=0;		
		father[i]=-1;    
    }
   
    //------------------------------------------------
    used[0]=1;                 //把第0个顶点归入集合u中
	for(i=0;i<vcount;i++)
	{
	    lowcost[i]=G[0][i];    //把各顶点到顶点0的权值保存在lowcost[i]中
	}
    //----------------------------------------------------
    for (i=1;i<vcount;i++)   //循环次数:n个顶点,进行n-1次即可 (  u={v0}, 剩下的顶点{v1,.......} 开始生成最小生成树)
    {       
        //求最小值
		min=infinity;
		for(m=0;m<vcount;m++)
		{
		   if(used[m]==0 && lowcost[m]<min)
		   {
		      min=lowcost[m];
			  j=m;
		   }
		}

		father[j]=closeset[j];  //记录j的前领结点
        used[j]=1;              //把顶点j并入u中
		

        for (k=0;k<vcount;k++)                   //新顶点并入u后重新选择最小边(针对lowcost[k]的修改)
		{
            if (!used[k]&&(G[j][k]<lowcost[k]))  
            { 
				lowcost[k]=G[j][k];  
                closeset[k]=j; 
			}
		}
   } 
	
   //自己加的:最小生成树的生成
   for(m=0;m<vcount;m++)    
   {
       if(father[m]!=-1)
	   {
	      printf("v%d-v%d\t",father[m],m);     
	   }
   }
}



int juZhen(int g[][max_vertexes])
{
    int vCount=0,i=0,j=0,w=0,m=0,n=0;
	printf("功能:依输入数据构造带权无向图G,并输出G的最小生成树\n\n");
    
    printf("请输入图的顶点数,范围在1-%d\n",max_vertexes);      //输入顶点个数
	scanf("%d",&vCount);
	while(vCount<0 || vCount>max_vertexes)
	{
	   printf("顶点个数输入有误,请重新输入");
       scanf("%d",&vCount);
	}
    printf("则顶点的范围在0-%d\n",vCount-1);

    for(m=0;m<vCount;m++)  	                                 //图的矩阵初始化
	{
	   for(n=0;n<vCount;n++) 
	   {
	        g[m][n]=infinity;     //默认权值为无穷大
	   }
	}

    printf("请输入图中边所连顶点i与j,及边的权值,以 -1 -1 -1为结束标志\n");  //图的矩阵
    scanf("%d %d %d",&i,&j,&w);
	while(i!=-1 && j!=-1 && w!=-1)
    {
	    //对顶点i j范围限制
		if(i<0 ||i>=vCount || j<0 ||j>=vCount)
		{ 
			printf("顶点输入有误,请重新输入\n");
			continue;		
		}
		else
		{
		    g[i][j]=w; 
			g[j][i]=w;
		}
        scanf("%d %d %d",&i,&j,&w);
	}
	return vCount;
}