/*
这个题目同时用到了并查集和最小生成树
用并查集判断所有点是否符合条件
在利用最短路计算最小价值
*/
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int Maxn = 1000000;
const int maxn = 105;
double dis[maxn][maxn], cost[maxn], dist;
int vis[maxn], n;
struct Point//建立结构体Point来保存点的坐标
{
double x, y;
} p[maxn];
double Compute(double x1, double y1, double x2, double y2)//计算两点之间距离的函数
{
return sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
}
int Find(int t)
{
if(vis[t] != t)
vis[t] = Find(vis[t]);
return vis[t];
}
void Merge(int a, int b)//并查集函数,将属于同一个集合的点放在同一个集合中
{
int x, y;
x = Find(a);
y = Find(b);
if(x < y) vis[y] = x;
else vis[x] = y;
}
void Prim()//最短路函数
{
cost[1] = 0;
for(int i = 2; i <= n; i++)
cost[i] = dis[1][i];
int temp, m;
for(int i = 2; i <= n; i++)
{
temp = Maxn;
m = 0;
for(int j = 1; j <= n; j++)
{
if(cost[j]<temp && cost[j]!=0)
{
temp = cost[j];
m = j;
}
}
dist += cost[m];
cost[m] = 0;
for(int j = 1; j <= n; j++)
{
if(cost[j] > dis[m][j])
cost[j] = dis[m][j];
}
}
}
int main()
{
int t;
cin >> t;
while(t--)
{
dist = 0;
cin >> n;
for(int i = 1; i <= n; i++)
{
cin >> p[i].x >> p[i].y;
vis[i] = i;
}
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
{
double d = Compute(p[i].x,p[i].y,p[j].x,p[j].y);
if(d>=10 && d<=1000)//将满足条件的距离乘以100以费用的形式保存在dis数组中
{
dis[i][j] = dis[j][i] = d*100;
Merge(i,j);//将能够连接在一起的结点合并到一个集合中
}
else dis[i][j] = dis[j][i] = Maxn;//将距离小于10或者大于1000的两点距离剔除
}
int cont = 0;
for(int i = 1; i <= n; i++)//统计集合的个数
if(vis[i] == i) cont++;
if(cont != 1)//只有集合个数为1时才能将所有的点连接起来
{
cout << "oh!" << endl;
continue;
}
Prim();
printf("%.1lf\n",dist);
}
return 0;
}
HDU 1875 Prim+并查集
最新推荐文章于 2018-07-18 23:22:05 发布