HDOJ-1875-畅通工程再续 解题报告

       一道最小生成树题目。题意为中文描述不多说。比起一般的最小生成树题目来说,本题需要考虑浮点数的比较,另外对边长也有限制(如题目所说:两岛之间的距离不能小于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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值