题意:平面坐标系中有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; }