ZOJ 1203 - Swordfish

并查集 - Kruskal

第一次敲并查集,裸题,很好过。

 

 

 

题意:有n个城市,每个城市有它的坐标,连接这n个城市所需的线路长度的最小值。

 

分析:在本题中,任意两个点之间都有边连通,其权值是两城市之间的距离,将边存入edge[]数组里,用Kruskal求解。

 

AC代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define MAXN 105
#define MAXM 5000

struct Edge  //边
{
    int u, v;
    double w;
}e[MAXM];

int p[MAXM];  //p[i]为节点i在集合中对应的树中的根节点
double x[MAXN], y[MAXN];  //城市坐标
int n, m;  //点,边个数
double sum;  //权值和

int Find(int x)  //找x所在集合的根节点
{
    int s;
    for(s=x; p[s]>=0; s=p[s])
    while(s!=x)
    {
        int tmp = p[x];
        p[x] = s;
        x = tmp;
    }
    return s;
}
void Union(int R1, int R2)  //合并
{
    int r1 = Find(R1);
    int r2 = Find(R2);
    int tmp = p[r1] + p[r2];
    if(p[r1] > p[r2])
    {
        p[r1] = r2;
        p[r2] = tmp;
    }
    else
    {
        p[r2] = r1;
        p[r1] = tmp;
    }
}

int cmp(const struct Edge *a, const struct Edge *b)
{
    if(a->w > b->w) return 1;
    else return -1;
}

void Kruskal()
{
    int num = 0;
    int u, v, i;
    memset(p, -1, sizeof(p));
    for(i=0; i<m; i++)
    {
        u = e[i].u;
        v = e[i].v;
        if(Find(u) != Find(v))
        {
            sum += e[i].w;
            num++;
            Union(u, v);
        }
    }
}

int main()
{
    int t = 1;
    while(scanf("%d",&n),n)
    {
        int i,j;
        double d;
        for(i=0; i<n; i++)
        {
            scanf("%lf%lf",&x[i],&y[i]);
        }
        int mm = 0;
        for(i=0; i<n; i++)  //更新edge数组
            for(j=i+1; j<n; j++)
            {
                d = sqrt( (x[i]-x[j])*(x[i]-x[j]) + (y[i]-y[j])*(y[i]-y[j]) );
                e[mm].u = i;
                e[mm].v = j;
                e[mm].w = d;
                mm++;
            }
        m = mm;
        qsort(e, m, sizeof(e[0]), cmp);  //边的权值按从小到大排列
        sum = 0.0;
        Kruskal();
        if(t>1) printf("\n");
        printf("Case #%d:\n", t);
        printf("The minimal distance is: %.2lf\n", sum);
        t++;
    }
    return 0;
}



 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值