一道最小生成树题目。题意为中文描述不多说。比起一般的最小生成树题目来说,本题需要考虑浮点数的比较,另外对边长也有限制(如题目所说:两岛之间的距离不能小于10米也不能大于1000米),也就是说在此情况下不能直接将两小岛连通。
我的解题思路:首先计算和比较浮点数的大小要尤其注意,其次根据题意,两岛之间的距离不满足题目要求的视做无法直接连通。注意这两点之后用kruskal算法或者prim算法解决就可以了。
下面是解题代码:kruskal解法
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define N 105
typedef struct side //定义边结构体
{
int a, b; //两点(岛)的下标
double len; //边长(距离)
}side;
typedef struct point //定义点结构体
{
int x, y; //坐标
}point;
point p[N];
side s[N*N];
int bleg[N]; //并查集使用,存储父节点
int pn; //点的数量
int sn; //边的数量
int t; //测试样例数
void Init(); //初始化
void Read(); //输入
double Count(int i, int j); //计算边长
void Kruskal();
int Mycmp(const void *a, const void *b); //qsort比较函数
int Find(int x); //并查集查找
void Union(int x, int y); //并查集合并
int Test(); //检测工程是否畅通
int main()
{
scanf("%d", &t);
while (t--)
{
Init();
Read();
Kruskal();
}
return 0;
}
void Init() //初始化
{
int i;
for (i=0; i<N; ++i)
{
bleg[i] = i;
}
sn = pn = 0;
return;
}
void Read() //输入
{
int i, j;
scanf("%d", &pn);
for (i=0; i<pn; ++i)
{
scanf("%d %d", &p[i].x, &p[i].y);
for (j=0; j<i; ++j) //开始计算新增的边
{
s[sn].a = i;
s[sn].b = j;
s[sn++].len = Count(i, j);
}
}
return;
}
double Count(int i, int j) //计算边长
{
double dx = ((double)p[i].x - p[j].x) * (p[i].x - p[j].x);
double dy = ((double)p[i].y - p[j].y) * (p[i].y - p[j].y);
return sqrt(dx + dy);
}
void Kruskal()
{
int i;
double ans = 0;
qsort(s, sn, sizeof(side), Mycmp);
for (i=0; i<sn; ++i) //忽略边长小于10的边
{
if (s[i].len >= 10) break;
}
for (; i<sn; ++i)
{
if (s[i].len <= 1000 && Find(s[i].a) != Find(s[i].b)) //要求边长小于等于1000
{
ans += s[i].len;
Union(s[i].a, s[i].b);
}
}
if (Test() == 1)
{
printf("%.1f\n", 100 * ans);
}
else
{
printf("oh!\n");
}
return;
}
int Mycmp(const void *a, const void *b) //qsort比较函数
{
if ((*(side *)a).len > (*(side *)b).len)
{
return 1;
}
return -1;
}
int Find(int x) //并查集查找
{
int y = bleg[x];
int z;
while (y != bleg[y])
{
y = bleg[y];
}
while (x != bleg[x])
{
z = bleg[x];
bleg[x] = y;
x = z;
}
return y;
}
void Union(int x, int y) //并查集合并
{
int fx = Find(x);
int fy = Find(y);
bleg[fx] = fy;
return;
}
int Test() //检测工程是否畅通
{
int i;
int x = bleg[0];
for (i=1; i<pn; ++i)
{
if (bleg[i] != x) //出现有两小岛不属于同一个集合时说明工程未畅通
{
return 0;
}
}
return 1;
}