没往最小生成树那边想,想了下dijstra发现正好能解决。
评测记录,前九个点还挺快,最后一个点T了。
#include<stdio.h>
#include<vector>
#include<math.h>
#define int long long//全是long long
int cnt,head[1005],to[1005],ne[1005],x[1005],y[1005],q[1005],qq;
double ans[1005];
using namespace std;
void dfs(int a)
{
int i;
q[qq++]=a;//新的点放进q数组,之后会用到
ans[a]=0;//为零就表示访问过了
for(i=head[a];i;i=ne[i])
if(ans[to[i]])
dfs(to[i]);
}
signed main()
{
int n,m,i,j,a,b,cu,min;
double dis,sum=0;
scanf("%lld%lld",&n,&m);
for(i=1;i<=n;i++)
scanf("%lld%lld",&x[i],&y[i]);
for(i=0;i<m;i++)
{
scanf("%lld%lld",&a,&b);
if(a==b)
continue;
cnt++;//链式前向星存图
ne[cnt]=head[a];
to[cnt]=b;
head[a]=cnt;
cnt++;
ne[cnt]=head[b];
to[cnt]=a;
head[b]=cnt;
}
for(i=1;i<=n+1;i++)//ans[i]为0表示已进入集合,否则表示已进入集合的点到第i个点最短的直线距离
ans[i]=(int)1<<63-1;
cu=1;//从节点1开始
while(1)
{
qq=0;//qq记录了与cu连通且未在集合中的点的数量,这些点存在q数组中
dfs(cu);
min=n+1;
for(i=0;i<qq;i++)//i跑一遍所有新进入集合的点,计算节点i到其他所有未在集合中的节点的距离
for(j=1;j<=n;j++)
if(ans[j])//未在集合
{
dis=sqrt((x[q[i]]-x[j])*(x[q[i]]-x[j])+(y[q[i]]-y[j])*(y[q[i]]-y[j]));
if(dis<ans[j])//如果更优,就更新
ans[j]=dis;
}
for(i=1;i<=n;i++)
if(ans[i]&&ans[i]<ans[min])//找一个未在集合且最优的,dijstra
min=i;
if(min==n+1)//说明所有点都在集合里了,结束
break;
sum+=ans[min];//把这条边加上
cu=min;
}
printf("%.2lf",sum);
}
时间复杂度应该是n2或者n*m
while(1)
for(i=0;i<qq;i++)
这俩复杂度相乘是n,因为第一个循环次数是连通分量的个数,第二个循环次数是每个连通分量里点的个数。