POJ-2560-Freckles 解题报告

       一个普通的最小生成树问题,kruskal算法或prim算法解决,我用的kruskal,因为目前我只会这个。题目意思是给你那什么长在身上的雀斑的坐标,然后问你能够使每个雀斑都连在一起所需要的最少油墨长度。


       kruskal解法:首先要把每两个点构成的边的边长计算出来,然后把这些边按照长度由小到大来排序,把边从小到大一次加入最小生成树中,如果加入的边会构成环的话就不加入(并查集实现,当边上的两点属于同一集合就说明加入后会构成环),最后输出这些边的总长度就可以了。


       注意:我的代码在c和c++编译器中能通过,在gcc和g++编译器中则会WA,因为在gcc和g++中double类型的输出是%f,也就是说将输出改成%f在gcc和g++就能通过,而在c和c++则依旧能通过,说明%f用来输出double类型在这些编译器中都是可以的。(感觉有点反常理,但事实是这样、、、)


       下面附上我的解题代码,kruskal算法:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define N 110

typedef struct point    //定义点的结构体
{
    double x, y;    //坐标
}point;
typedef struct side     //定义边的结构体
{
    int a, b;   //两点的下标
    double len; //边长
}side;

point p[N];
side s[N*N];
int bleg[N];        //存储父节点
int pn;             //点的数量
int sn = 0;         //边的数量
double ans = 0;     //答案

void Init();        //初始化

void Read();        //输入点并且计算边

double Count(int x, int y);     //计算边长

int Find(int x);    //查找操作,用于判断是否成环

void Union(int x, int y);   //合并操作

int Mycompare(const void *a, const void *b);    //用于qsort的排序比较函数

void Link();        //将边连接起来构造并计算最小生成树

int main()
{
    scanf("%d", &pn);
    Init();
    Read();
    qsort(s, sn, sizeof(s[0]), Mycompare);
    Link();
    printf("%.2lf\n", ans);     //如果输出为%.2f的话则在以上4种编译器中都能通过
    return 0;
}

void Init()     //初始化
{
    int i;
    for (i=0; i<N; ++i)
    {
        bleg[i] = i;
    }
    ans = 0;
    return;
}

void Read()         //输入点并且计算边
{
    int i, j;
    for (i=0; i<pn; ++i)
    {
        scanf("%lf %lf", &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 x, int y)      //计算边长
{
    double lx = (p[x].x - p[y].x) * (p[x].x - p[y].x);
    double ly = (p[x].y - p[y].y) * (p[x].y - p[y].y);
    double len = sqrt(lx + ly);
    return len;
}

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 Mycompare(const void *a, const void *b)     //用于qsort的排序比较函数
{
    if ((*(side *)a).len > (*(side *)b).len)
    {
        return 1;
    }
    return -1;
}

void Link()     //将边连接起来构造并计算最小生成树
{
    int i;
    for (i=0; i<sn; i++)
    {
        if (Find(s[i].a) != Find(s[i].b))
        {
            Union(s[i].a, s[i].b);
            ans += s[i].len;
        }
    }
    return;
}

    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值