解析:最小生成树;Kruskal 算法:并查集实现。
1、首先找出符合要求的边;
2、对找出的边排序;
3、并查集找出n-1条边,无法修通n-1条路则无法实现要求。
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
struct Point
{
int x,y;
} point[102];
struct Edge
{
int a,b;
double v;
bool operator<(const Edge a)
{
return v<a.v;
}
} edge[5002];
int p[102];
double Distance(Point a,Point b)
{
return sqrt(pow(a.x-b.x,2.0)+pow(a.y-b.y,2.0));
}
bool Init(int n) //一开始指向自己
{
for(int i=0;i<=n;i++)
p[i]=i;
return true;
}
int Find(int x) //找到根节点
{
int r,i,j;
r=x;
while(r!=p[r]) r=p[r]; //路径压缩准备,找到根节点
i=x;
while(i!=p[i])
{
j=p[i];
p[i]=r;
i=j;
}
return i; //返回根节点
}
bool Merge(int x,int y) //返回是否需要合并
{
int tx,ty;
tx=Find(x);
ty=Find(y);
if(tx==ty) return false;
p[tx]=ty;
return true;
}
int main()
{
int T,C,i,j,k,cnt;
int tx,ty;
double dis,sum;
scanf("%d",&T);
while(T--)
{
scanf("%d",&C);
k=0;
for(i=1;i<=C;i++)
{
scanf("%d%d",&point[i].x,&point[i].y);
for(j=1;j<i;j++)
{
dis=Distance(point[i],point[j]);
if(dis>=10 && dis<=1000) //计算满足要求的边
{
edge[k].a=i;
edge[k].b=j;
edge[k++].v=dis;
}
}
}
Init(C);
sort(edge,edge+k);
cnt=C-1;
sum=0;
for(i=0;i<k;i++)
{
tx=Find(edge[i].a);
ty=Find(edge[i].b);
if(tx!=ty) //增加一条路,知道增加完C-1条
{
Merge(tx,ty);
sum+=edge[i].v;
cnt--;
if(cnt==0) break;
}
}
if(!cnt) //cnt不为0就不能修C-1条路
printf("%.1lf\n",sum*100);
else puts("oh!");
}
return 0;
}
HDU ACM : 1875 畅通工程再续->最小生成树(并查集)
原文地址:http://blog.csdn.net/a809146548/article/details/44277567