• Prim算法,最小生成树 HDU 1233


      Prim算法用于求无向图的最小生成树

    设图G =(V,E),是一个具有n个顶点的带权连通图,T=(U,TE)是G的最小生成树,期中U是T的顶点集,TE是T的边集,则从V0开始构造最小生成树T的步骤如下:

    (1)      初始化 = {V0}将V0到其他顶点的所有边作为候选边。

    (2)      重复以下步骤n-1次,使得其他n-1个顶点被加入到U中。

    1. 从候选边中挑选权值最小的边输出,设该边在V-U中的顶点是V,将V加入U中,删除和V关联的边。
    2. 考察当前V-U中的所有顶点Vi,修正候选边。若(V,Vi)的权值小于原来和Vi关联的候选边,则用(V,Vi)取代后者作为候选边。
    void Prim(int n,int Graph[][MAXN],int * pre)
    {
    	int vset[MAXN],lowcost[MAXN];//lowcost[MAXN]表示存放顶点到为完成的生成树的最小权值
    								//v[MAXN]表示该结点是否已经在生成树里 
    	int i,j,k;				
    	for(i = 0 ; i < n; i++)		//赋初始值,将每个结点的连接到生成树的权值赋值为最大,所有结点均未在生成树中
    								//所有结点的前驱都是-1,表示没有任何结点与之相连 
    	{lowcost[i] = INF;vset[i] = 0;pre[i] = -1;}
    	
    	for(lowcost[j = 0] = 0;j < n; j++)//分别将连通图中n个结点,加入到最小生成树中
    	{
    		for(k = -1,i = 0; i < n; i++)//第一次循环将k 赋值 -1,这样找到第一个没有加入到生成树中的结点,之后k值改变
    		{							//继续循环,寻找不在生成树中的结点到生成树的权值最小的那个结点,将其链接到生成树上
    			if(vset[i] == 0 &&(k == -1 || lowcost[i] < lowcost[k]))
    				k = i;
    		}
    		printf("edge(%d,%d)的权值为%d,被加入生成树中\n",pre[k]+1,k+1,lowcost[k]);
    		vset[k] = 1;				//将选中的结点做好标记 
    		
    		for(i = 0 ; i < n; i++)		//修正候选边,每次记录入选的结点k之后。分别记录其他结点到生成树的最小权值
    		{
    			if(vset[i] == 0 && Graph[k][i] < lowcost[i])
    			{
    
    				lowcost[i] = Graph[k][i];	
    				pre[i] = k;				//pre记录i结点到生成树最小权值是连接在k结点上
    			}
    		} 
    	} 
    }
    

    HDU 1233 还是畅通工程

    Problem Description
    某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。
     
    Input
    测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
    当N为0时,输入结束,该用例不被处理。
     
    Output
    对每个测试用例,在1行里输出最小的公路总长度。
     
    Sample Input
    31 2 11 3 22 3 441 2 11 3 41 4 12 3 32 4 23 4 50
     
    Sample Output
    35
    #include <iostream>
    using namespace std;
    
    //无向图最小生成树,prim算法,邻接阵形式,复杂度O(n^2)
    //返回最小生成树的长度,传入图的大小n和邻接阵mat,不相邻点边权inf
    //可更改边权的类型,pre[]返回树的构造,用父结点表示,根节点(第一个)pre值为-1
    //必须保证图的连通的!
    #define MAXN 200
    #define inf 1000000000
    typedef int elem_t;
    
    elem_t prim(int n,elem_t mat[][MAXN],int* pre)
    {
    	elem_t min[MAXN],ret=0;			//min[MAXN]表示存放顶点到为完成的生成树的最小权值,ret作为本题的结果,
    									//ret为本题最小生成树所有边的权值总和 
    	int v[MAXN],i,j,k;				//v[MAXN]表示该结点是否已经在生成树里,如果在则为1,否则为0 
    
    	for (i=0;i<n;i++)				//赋初始值,将每个结点的连接到生成树的权值赋值为最大,所有结点均未在生成树中 
    		min[i]=inf,v[i]=0,pre[i]=-1;
    		
    	for (min[j=0]=0;j<n;j++)		//分别将连通图中n个结点,加入到最小生成树中 
    	{ 
    		for (k=-1,i=0;i<n;i++)		//第一次循环将k 赋值 -1,这样找到第一个没有加入到生成树中的结点,之后k值改变,
    									//继续循环,寻找不在生成树中的结点到生成树的权值最小的那个结点,将其链接到生成树上 
    			if (!v[i]&&(k==-1||min[i]<min[k]))
    					k=i;  
    					
    		for (v[k]=1,ret+=min[k],i=0;i<n;i++)//修正候选边,每次记录入选的结点k之后。分别记录其他结点到生成树的最小权值 
    			if (!v[i]&&mat[k][i]<min[i])
    				min[i]=mat[pre[i]=k][i];	//pre记录i结点到生成树最小权值是连接在k结点上 
    	}
    	return ret;
    }
    int mat[MAXN][MAXN], pre[MAXN];
    int main() 
    {
    	int n, i, j, u, v, c;
    	while (scanf("%d", &n) != EOF) 
    	{
    		if (n == 0) break;
    		for (i = 0; i < n * (n - 1) / 2; i++) 
    		{
    			scanf("%d%d%d", &u, &v, &c);
    			
    			u--, v--;
    			mat[u][v] = mat[v][u] = c;
    		}
    		printf("%d\n", prim(n, mat, pre));
    	}
    	return 0;
    }
    
    
    
  • 相关阅读:
    [leetcode] Valid Sudoku
    [leetcode] Count and Say
    [leetcode] Decode Ways
    [leetcode] Sqrt(x)
    [leetcode] Best Time to Buy and Sell Stock II
    7-27 兔子繁衍问题
    7-26 最大公约数和最小公倍数
    7-25 求奇数和
    7-24 猜数字游戏
    7-23 分段计算居民水费
  • 原文地址:https://www.cnblogs.com/newwy/p/1865589.html
Copyright © 2020-2023  润新知