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

来源:互联网 发布:淘宝上的百度财富 编辑:程序博客网 时间:2024/06/14 05:58

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

Input

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

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

Output

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

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

Sample Input

40 0 0 00 1 1 01 1 1 00 0 0 1

Sample Output

3 3.4142 1.4142

Hint

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

我们知道,2维 空间 上的距离 d = \sqrt{x^2+y^2}

我们知道,3维 空间 上的距离 d = \sqrt{x^2+y^2+z^2}

类似地, 4维 时空 上的距离 d = \sqrt{x^2+y^2+z^2+t^2}

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 0x7F800000int 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=0doubletmp=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;}

0 0