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