题意:平面坐标系中有N个点,其中部分点之间已经连通。在这个图上补充边,使整个图连通,且边的总长度最小。
思路:类似于最小生成树,Prim算法一开始没想出来思路,就用Kruskal写了。已经连接的点并到一个集合里,求剩下部分的最小生成树。。。话说用这种方法效率有点低,占内存还大,但是对于这个数据量还是能过的。
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <cstdlib>
#include <string>
#include <memory.h>
#include <vector>
#include <queue>
#include <stack>
#include <ctype.h>
using namespace std;
struct point{
int x;
int y;
};
point pt[800];
int parent[800];
int get_p(int i){
if(parent[i]!=i){
parent[i]=get_p(parent[i]);
}
return parent[i];
}
void uni(int a,int b){//合并
if(get_p(a)!=get_p(b)){
parent[get_p(b)]=get_p(a);
}
}
double dist(point a,point b){//两点距离
return sqrt((double)(a.x-b.x)*(a.x-b.x)+(double)(a.y-b.y)*(a.y-b.y));
}
struct edge{
int u;
int v;
double len;
};
edge E[562510];
bool cmp(edge a,edge b){
return a.len<b.len;
}
int main(){
int n;
while(cin>>n){
//init
for(int i=0;i<800;i++){
parent[i]=i;
}
//
for(int i=1;i<=n;i++){
scanf("%d%d",&pt[i].x,&pt[i].y);
}
//calc all distances
int k=0;
for(int i=2;i<=n;i++){
for(int j=1;j<i;j++){
E[k].len=dist(pt[i],pt[j]);
E[k].u=i;
E[k++].v=j;
}
}
sort(E,E+k,cmp);
int m;
cin>>m;
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
uni(u,v);//已经存在边的点并起来
}
double ans=0.0;
for(int i=0;i<k;i++){//这里写坑了,连完以后没有跳出
if(get_p(E[i].u)!=get_p(E[i].v)){
ans+=E[i].len;
uni(E[i].u,E[i].v);
}
}
printf("%.2lf\n",ans);
}
return 0;
}