POJ-1789-Truck History 解题报告

       一道求最小生成树的水题,数据十分水,属于稠密图,适合用prim算法,不过本人还是用的kruskal算法(表示目前还不会prim算法)。题意:以一个由七位小写字母组成的字符串为车辆编号,每辆车的编号只能由另一辆车的编号衍生出来(第一辆车不算),衍生的代价为编号中对应位字母不相同的个数。比如aaaaaaa与baaaaaa有一个位的字母不相同,因此它们互相衍生出来的代价是1。又比如在baaaaaa与abaaaaa有两个对应位的字母不同,因此它们互相衍生的代价是2。在样例中,很明显当第二,三,四辆车的编号都由第一辆车编号衍生出来时代价最小,分别为1,1,1。因此总代价为3。题目要求求出这些车辆编号的最小衍生总代价,就是求它们的最小生成树。


       题目数据比较水,初步估计没有当N=2000的极限数据。这道题一直错,我查错查了很久,最后发现原来是没有做多组输入中当输入N=0时结束程序的特殊判断(囧),还是不够细心……


       下面是我的解题代码

#include <stdio.h>
#include <stdlib.h>
#define N 2010
#define M 10

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

side s[N*N];
int bleg[N];        /*并查集使用,存储父节点*/
char type[N][M];
int ans;
int n;
int sn;     /*边的数量*/

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

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

int Mycmp(const void *a, const void *b);

void Link();        /*连接边构成最小生成树*/

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

int Find(int x);        /*查找*/

void Union(int x, int y, int i);        /*合并,根据题目增加特殊操作*/

int main()
{
    while (~scanf("%d", &n))
    {
        if (n == 0) break;      /*忘了写这个,一直WA(囧)*/
        Init();
        Read();
        qsort(s, sn, sizeof(side), Mycmp);
        Link();
    }
    return 0;
}

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

void Read()     /*输入点并且计算边*/
{
    int i, j;
    for (i=0; i<n; i++)
    {
        scanf("%s", type[i]);
        for (j=0; j<i; j++)     /*计算新增加的边*/
        {
            s[sn].a = i;
            s[sn].b = j;
            s[sn++].len = Count(i, j);
        }
    }
    return;
}

int Count(int x, int y)     /*计算边长*/
{
    int i;
    int num = 0;
    for (i=0; i<7; i++)
    {
        if (type[x][i] != type[y][i])
        {
            num++;
        }
    }
    return num;
}

int Mycmp(const void *a, const void *b)
{
    return (*(side *)a).len - (*(side *)b).len;
}

void Link()         /*连接边构成最小生成树*/
{
    int i;
    for (i=0; i<sn; i++)
    {
        Union(s[i].a, s[i].b, i);
    }
    printf("The highest possible quality is 1/%d.\n", ans);
    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 i)     /*合并,根据题目增加特殊操作*/
{
    int fx = Find(x);
    int fy = Find(y);
    if (fx == fy) return;
    ans += s[i].len;        /*计算最小生成树的边长*/
    bleg[fx] = fy;
    return;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值