问题来了:怎样才能在以最少虫洞的情况下,并且虫洞的长度总和最小,使一个时空星系中所有星球连接在一起?
有许多组测试数据,每组测试数据中,第一行一个n(2<=n<=2000),表示某星系恒星的数量.
接下来n行,每行4个整型数据x,y,z,t(0<=x,y,z,t<=1000).表示恒星在宇宙中的空间坐标点以及时间的维度t(忽略计算恒星的体积大小)。
输出1行,包含三个数字(用一个空格区分,注意最后一个数字后面没空格).
第一个是需要虫洞的数量,第二个是所有虫洞总长度之和(输出后4位小数).第三个是最长的虫洞的长度(输出后4位小数).
4 0 0 0 0 0 1 1 0 1 1 1 0 0 0 0 1
3 3.4142 1.4142
我们知道,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; }
克鲁斯卡尔算法
#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; }