POJ-1789-Truck History 解题报告

来源:互联网 发布:微小宝类似软件 编辑:程序博客网 时间:2024/05/22 13:14

       一道求最小生成树的水题,数据十分水,属于稠密图,适合用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 10typedef 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;}

0 0