SZUOJ-Problem(J16):Bright stars最小生成树

问题来了:怎样才能在以最少虫洞的情况下,并且虫洞的长度总和最小,使一个时空星系中所有星球连接在一起?

Input

有许多组测试数据,每组测试数据中,第一行一个n(2<=n<=2000),表示某星系恒星的数量.

接下来n行,每行4个整型数据x,y,z,t(0<=x,y,z,t<=1000).表示恒星在宇宙中的空间坐标点以及时间的维度t(忽略计算恒星的体积大小)。

Output

输出1行,包含三个数字(用一个空格区分,注意最后一个数字后面没空格).

第一个是需要虫洞的数量,第二个是所有虫洞总长度之和(输出后4位小数).第三个是最长的虫洞的长度(输出后4位小数).

Sample Input

4
0 0 0 0
0 1 1 0
1 1 1 0
0 0 0 1

Sample Output

3 3.4142 1.4142

Hint

我们知道,1维 空间 上的距离d=x

我们知道,2维 空间 上的距离

我们知道,3维 空间 上的距离

类似地, 4维 时空 上的距离

Sample中 0 0 0 0,我们可以想象为是地球,而0 1 1 0是木星,1 1 1 0是金星,0 0 0 1是未来1个世纪后的地球。

还有的是,注意星球的数量有点多,大家注意处理。

 代码1

prim算法

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
#define INF 0x7F800000

int mtx[2005][5];

int dist[2005];

int getDist(int i,int j)
{
	int ret = (mtx[i][1]-mtx[j][1])*(mtx[i][1]-mtx[j][1])
		+(mtx[i][2]-mtx[j][2])*(mtx[i][2]-mtx[j][2])
		+(mtx[i][3]-mtx[j][3])*(mtx[i][3]-mtx[j][3])
		+(mtx[i][4]-mtx[j][4])*(mtx[i][4]-mtx[j][4]); 
    return ret;
}


int main()
{
	int t,n,i,j,k;
	while(	scanf("%d",&n)!=EOF)
	{ 	
		for (k=1;k<=n;k++)
			scanf("%d%d%d%d",&mtx[k][1],&mtx[k][2],&mtx[k][3],&mtx[k][4]);
		
		
		
		for (j=1;j<=n;j++)           //创建第一组dist
		{  dist[j]=getDist(1,j);} 
		double ans=0;
		double tmp=0;
		for (k=2;k<=n;k++)                     //不断更新dist
		{
			int minEdge=INF;
			int minpoint;        //   minEdge记录当前往外扩展的最小非零边权,minPoint记录对应边指向的节点编号
			
			for (j=1;j<=n;j++)                     //不断更新dist
			{
				if (dist[j]!=0 && dist[j]<minEdge)  //找到最小加权边与点
				{
					minEdge=dist[j];
					minpoint=j;
				}
			}
			
			if (tmp<minEdge)  
				tmp=minEdge;
			
			dist[minpoint]=0;       //将当前节点标记为已加入生成树,dist值置零
			
			ans+=sqrt(minEdge);           //累计生成树的路径长度
			
			for (j=1;j<=n;j++)                    ////用此节点一一跟新其他点的dist值
			{
				
				if (  getDist(minpoint,j)<dist[j]   )
					dist[j]=(getDist(minpoint,j));
			} 
		} 
		
		printf("%d %.4lf %.4lf\n",n-1,ans,sqrt(tmp) );
		
		
	}
	return 0;
} 

代码2

克鲁斯卡尔算法

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int g[2005];
int f[2005][5];
 
int find(int x)   //x所在集合的根
{
	if(x==g[x]) return x;
	return g[x]=find(g[x]);
}
 
 
struct aaaa
{
	int u,v;
	int weight;	
};
 
aaaa edge[2000003]; 
 
bool cmp(aaaa a,aaaa b)  
{  
	return  (a.weight<b.weight);
}
 
int main() 
{ 
	int t,n,i,j,k,pp,s,p;
	while(scanf("%d",&t)!=EOF)
	{
		for (i=1;i<=t;i++)
		{	
			scanf("%d%d%d%d",&f[i][1],&f[i][2],&f[i][3],&f[i][4]);
		}	
		for(int j=1;j<=t;j++) g[j]=j;  //初始化为自己////////**********************
 
 
		int ko=1;
		for (j=1;j<=t;j++)
		{
			for (k=j+1;k<=t;k++)
			{
				edge[ko].u=j;
				edge[ko].v=k;
				edge[ko].weight= 	(  (f[j][1]-f[k][1])*(f[j][1]-f[k][1])+(f[j][2]-f[k][2])*(f[j][2]-f[k][2])+(f[j][3]-f[k][3])*(f[j][3]-f[k][3])+(f[j][4]-f[k][4])*(f[j][4]-f[k][4])         );  
				ko++;
 
 
			}
		} 
 
 
	 	sort(edge+1,edge+ko,cmp);
 
		double z=0;
		int z1=0;
 
		double	tmp=edge[1].weight;
		for (j=1;j<=t*(t-1)/2;j++)
		{ 
			int sb=find( edge[j].v);               //找根
			int sa=find( edge[j].u);          //找根
			if ( sa!=sb )
 
			{ 
				g[sb]=sa;				       
 
				if (edge[j].weight>tmp) tmp=edge[j].weight;
				z+=sqrt(edge[j].weight);
				z1++;
				if (z1>=(t-1)) break;
 
 
 
 
			}
 
		}
		printf("%d %.4lf %.4lf\n", z1,z,sqrt(tmp));
	}
 
 
 
	return 0;
}

你可能感兴趣的:(SZUOJ-Problem(J16):Bright stars最小生成树)