POJ-1861-Network 解题报告

       这是一道求最小生成树的题目。有kruskal算法和prim算法这两种解决最小生成树问题的算法。题意是说有n个点(2<=n<=1000且点的编号从1开始),m个连通方案(1<=m<=15000),并且每个连通方案都有需要消耗电缆的长度。要求从这些连通方案中选取一部分使得所有点都构成一个网络(点与点之间可以有其他的点互相连通。不要构成环,可用并查集实现)并且使所用方案中的最大消耗电缆长度尽量小,然后输出所用方案中最大消耗电缆长度,使用方案数以及每个方案的点的编号。


       接下来讲解题思路,输入n和m后依次输入m个连通方案,把连通方案根据消耗电缆长度也就是边的长度按照升序排序,然后遍历方案,当方案中的两个点没有连通(也就是不属于一个集合),那么执行该方案(合并两点)。最后输出方案中的最大电缆消耗长度(也就是最长边),使用方案数和每个方案连通的两个点。这是标准kruskal算法。


       注意实际上POJ上的这道题样例是有错误的,可以无视。另外这道题是特殊评测,所以有多种输出方案。


       接下来是我的解题代码,kruskal算法:

#include <stdio.h>
#include <stdlib.h>
#define N 1001
#define M 15001 

typedef struct  /*定义方案结构体*/
{
    int x;
    int y;
    int len;    /*消耗电缆长度*/
    int flag;   /*标志变量,1代表使用该方案*/
}SIDE;

SIDE side[M];
int bleg[N];    /*存储节点*/
int n, m;

void ReadSort();    /*输入方案并为方案排序*/

int Mycompare(const void *a, const void *b);    /*方案的比较函数,qsort函数需要*/

int Find(int x);

void Union(int x, int y);

void Init();    /*初始化*/

int main()
{
    int i;
    int num = 0;    /*记录使用的方案数*/
    int len = 0;    /*记录方案中消耗的电缆最大长度*/
    scanf("%d %d", &n, &m);
    ReadSort();
    Init();
    for (i=0; i<m; i++)
    {
        if (Find(side[i].x) != Find(side[i].y)) /*如果两点没有连通*/
        {
            len = side[i].len;
            num++;
            side[i].flag = 1;
            Union(side[i].x, side[i].y);
        }
    }
    printf("%d\n%d\n", len, num);
    for (i=0; i<m; i++)
    {
        if (side[i].flag == 1)
        {
            printf("%d %d\n", side[i].x, side[i].y);
        }
    }
    return 0;
}

void ReadSort()     /*输入与排序*/
{
    int i;
    for (i=0; i<m; i++)
    {
        scanf("%d %d %d", &side[i].x, &side[i].y, &side[i].len);
    }
    qsort(side, m, sizeof(SIDE), Mycompare);
    return;
}

int Mycompare(const void *a, const void *b)     /*排序比较函数*/
{
    SIDE *pa = (SIDE *)a;
    SIDE *pb = (SIDE *)b;
    if (pa->len != pb->len)
    {
        return (pa->len - pb->len);
    }
    else if (pa->x != pb->x)
    {
        return (pa->x - pb->x);
    }
    return (pa->y - pb->y);
}

void Init()     /*初始化函数*/
{
    int i;
    for (i=1; i<=n; i++)
    {
        bleg[i] = i;
    }
    for (i=0; i<m; i++)
    {
        side[i].flag = 0;
    }
    return;
}

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;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值