hdoj 1875 畅通工程再续 (最小生成树之prim算法)

                                                                             最小生成树

n使用不同的遍历图的方法,可以得到不同的生成树;从不同的顶点出发,也可能得到不同的生成树。
n按照生成树的定义,n个顶点的连通网络的生成树有 n个顶点、n-1条边。
n构造最小生成树的准则
n必须使用且仅使用该网络中的n-1条边来联结网络中的 n个顶点;
n不能使用产生回路的边;
n各边上的权值的总和达到最小。
       

  prim算法


普里姆算法的基本思想

    从连通网络 N = { V, E }中的某一顶点 u0 出发,选择与它关联的具有最小权值的边( u0, v ),将其顶点加入到生成树顶点集合U中。
   以后每一步从一个顶点在 U,而另一个顶点不在 U 中的各条边中选择权值最小的边(u, v),把它的顶点加入到集合 U中。如此继续下去,直到网络中的所有顶点都加入到生成树顶点集 U中为止。
     

采用邻接矩阵作为图的存储表示


hdoj 1875 畅通工程再续 (最小生成树之prim算法)_第1张图片

分析以上算法,设连通网络有 n个顶点则该算法的时间复杂度为 O(n2), 它适用于边稠密的网络。
注意:当各边有相同权值时,由于选择的随意性,产生的生成树可能不唯一。当各边的权值不相同时,产生的生成树是唯一的。
 

下面是杭电的一道例题     hdoj1875


畅通工程再续

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 20017    Accepted Submission(s): 6281


Problem Description
相信大家都听说一个“百岛湖”的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其他的小岛时都要通过划小船来实现。现在政府决定大力发展百岛湖,发展首先要解决的问题当然是交通问题,政府决定实现百岛湖的全畅通!经过考察小组RPRush对百岛湖的情况充分了解后,决定在符合条件的小岛间建上桥,所谓符合条件,就是2个小岛之间的距离不能小于10米,也不能大于1000米。当然,为了节省资金,只要求实现任意2个小岛之间有路通即可。其中桥的价格为 100元/米。
 

Input
输入包括多组数据。输入首先包括一个整数T(T <= 200),代表有T组数据。
每组数据首先是一个整数C(C <= 100),代表小岛的个数,接下来是C组坐标,代表每个小岛的坐标,这些坐标都是 0 <= x, y <= 1000的整数。
 

Output
每组输入数据输出一行,代表建桥的最小花费,结果保留一位小数。如果无法实现工程以达到全部畅通,输出”oh!”.
 

Sample Input
 
    
2 2 10 10 20 20 3 1 1 2 2 1000 1000
 

Sample Output
 
    
1414.2 oh!
 
  克鲁斯卡尔算法(已ac
#include
#include
#include
using namespace std;
int per[103];
void init()
{
	for(int i=0;i<=102;i++)  //由于上边定义的是103数组,此时只能访问0~102;不能用103这个位置,否则越界 
	per[i]=i;
}
struct node
{
	int  x;
	int  y;

}dao[103];
struct node2
{
	int  a;
	int  b;
	double changdu; 
}p[103*103];
double cmp(node2 a,node2 b)
{
	return a.changdu=10&&p[i].changdu<=1000)	
			{
				sum=sum+p[i].changdu;
				cnt++;
			}
		} 
		if(cnt>=m)
		printf("%.1lf\n",sum*100);   //double输出用lf 
		else
		printf("oh!\n") ;              	
	}
	return 0;
}


用克鲁斯卡尔大致有几个过程
1、建立编号。(找到两个点之间的联系,然后编号成第几组)
2、按照最小代价排序(一般为结构体排序)
3、利用并查集,边连接,边判断,排除成环的情况,并记录连接点的个数
4、判段连接点个数是否等于所需连接物体数量。
prim算法(ac)
#include
#include
#include
#define max 1000
#define INF 0xfffffff
int n;
int x[110],y[110];
double g[110][110];  
double dis(int a,int b)
{
	return sqrt(1.0*(x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]));
}
void prim()
{
	double dis[110],min,sum;
	int vis[110];
	int v,i,j,k;
	memset(vis,0,sizeof(vis));   //此数组为1时,代表进入集合,否则没进入集合 
	for(i=1;i<=n;i++)
	dis[i]=g[1][i];  //记录i点到集合1的距离 
	vis[1]=1;        //让第一个点进入集合 
	 for(v=1;vg[k][i])
		 dis[i]=g[k][i];   //注意dis记录的是集合内部距离集合外每一个点的最小距离,不是某个点 
	 } 
	    sum=0;
	   for(i=2;i<=n;i++)
	   sum+=dis[i]*100.0;
	   printf("%.1lf\n",sum) ;
	   return ;	 			 		
}
int main()
{
	int i,j,m;
	scanf("%d",&m);
	while(m--)
	{
		scanf("%d",&n);
		for(i=1;i<=n;i++)
		scanf("%d%d",&x[i],&y[i]);
		for(i=1;i<=n;i++)
			for(j=1;j<=n;j++)
			{
				g[i][j]=dis(i,j); //记录i点到j点的距离 
				if(g[i][j]<10||g[i][j]>1000)
				g[i][j]=INF;    //把不符合题意的点直接赋值无穷大,相当于做标记,便于输出 
			}
			prim();
	}
	return 0;
	
}


你可能感兴趣的:(最小生成树)