POJ-1789-Truck History 解题报告

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


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


       下面是我的解题代码

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #define N 2010
  4 #define M 10
  5 
  6 typedef struct side     /*定义边的结构体*/
  7 {
  8     int a, b;   /*两点的下标*/
  9     int len;    /*边长*/
 10 }side;
 11 
 12 side s[N*N];
 13 int bleg[N];        /*并查集使用,存储父节点*/
 14 char type[N][M];
 15 int ans;
 16 int n;
 17 int sn;     /*边的数量*/
 18 
 19 void Init();        /*初始化*/
 20 
 21 void Read();        /*输入点并且计算边*/
 22 
 23 int Mycmp(const void *a, const void *b);
 24 
 25 void Link();        /*连接边构成最小生成树*/
 26 
 27 int Count(int x, int y);        /*计算边长*/
 28 
 29 int Find(int x);        /*查找*/
 30 
 31 void Union(int x, int y, int i);        /*合并,根据题目增加特殊操作*/
 32 
 33 int main()
 34 {
 35     while (~scanf("%d", &n))
 36     {
 37         if (n == 0) break;      /*忘了写这个,一直WA(囧)*/
 38         Init();
 39         Read();
 40         qsort(s, sn, sizeof(side), Mycmp);
 41         Link();
 42     }
 43     return 0;
 44 }
 45 
 46 void Init()     /*初始化*/
 47 {
 48     int i;
 49     ans = 0;
 50     sn = 0;
 51     for (i=0; i<N; i++)
 52     {
 53         bleg[i] = i;
 54     }
 55     return;
 56 }
 57 
 58 void Read()     /*输入点并且计算边*/
 59 {
 60     int i, j;
 61     for (i=0; i<n; i++)
 62     {
 63         scanf("%s", type[i]);
 64         for (j=0; j<i; j++)     /*计算新增加的边*/
 65         {
 66             s[sn].a = i;
 67             s[sn].b = j;
 68             s[sn++].len = Count(i, j);
 69         }
 70     }
 71     return;
 72 }
 73 
 74 int Count(int x, int y)     /*计算边长*/
 75 {
 76     int i;
 77     int num = 0;
 78     for (i=0; i<7; i++)
 79     {
 80         if (type[x][i] != type[y][i])
 81         {
 82             num++;
 83         }
 84     }
 85     return num;
 86 }
 87 
 88 int Mycmp(const void *a, const void *b)
 89 {
 90     return (*(side *)a).len - (*(side *)b).len;
 91 }
 92 
 93 void Link()         /*连接边构成最小生成树*/
 94 {
 95     int i;
 96     for (i=0; i<sn; i++)
 97     {
 98         Union(s[i].a, s[i].b, i);
 99     }
100     printf("The highest possible quality is 1/%d.\n", ans);
101     return;
102 }
103 
104 int Find(int x)     /*查找*/
105 {
106     int y = bleg[x];
107     int z;
108     while (y != bleg[y])
109     {
110         y = bleg[y];
111     }
112     while (x != bleg[x])
113     {
114         z = bleg[x];
115         bleg[x] = y;
116         x = z;
117     }
118     return y;
119 }
120 
121 void Union(int x, int y, int i)     /*合并,根据题目增加特殊操作*/
122 {
123     int fx = Find(x);
124     int fy = Find(y);
125     if (fx == fy) return;
126     ans += s[i].len;        /*计算最小生成树的边长*/
127     bleg[fx] = fy;
128     return;
129 }

转载于:https://www.cnblogs.com/JZQT/p/3802449.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值