timus_1002_kmp_dijkstra
题目描述:
给定字母与数字的映射关系:
1 ij 2 abc 3 def
4 gh 5 kl 6 mn
7 prs 8 tuv 9 wxy
0 oqz
根据输入的数字字符串,和已经存在的字符串词典,求出符合给出的数字字符串的字符串序列,要求这个序列中字符串的个数最少
输入:
数字字符串
字典中包含的字符串个数
字符串 …
有多个case输入,数字字符串为-1结束所有的case输入
7325189087
5
it
your
reality
real
our
4294967296
5
it
your
reality
real
our
-1
输出:
reality our
No solution.
输出满足条件的任意一组字符串序列,如果没有满足条件的,输出No solution.
解题思路:
将目标数字串的下标作为图的顶点。对于给定的字典中的每个字符串,根据映射表转化为数字串,通过KMP算法,将这些数字串与输入的目标数字串匹配,获得匹配项的下标s,e,并认为顶点s-1与顶点e是有一条长度为1的边,如果有多条相同的边,取一条就可以了。对于不匹配的字符串直接忽略。题目所求就是找出从顶点0到顶点n-1的最小路径长度(n为目标数字串数字的个数)。
代码:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 5 //数字与字母关系映射表 6 char table[26] = {'2', '2', '2', '3', '3', '3', '4', '4', '1', '1', '5', '5', '6', '6', '0', '7', '0', '7', '7', '8', '8', '8', '9', '9', '9', '0'}; 7 8 //存放输入的数字串 9 char digital[101]; 10 int len_digital;//输入字符串的长度 11 12 //临时存放输入的字符串 13 char temp_string[51], temp_input[51]; 14 //输入的字母在输入数字串中的位置表示 15 char *position[100][100]; 16 17 //字典中单词的个数 18 int n; 19 //最小跳数的路径 20 int path[100]; 21 //0顶点到其他顶点的距离 22 int distance[100]; 23 int flag[100];//标记哪些顶点已经找到了最短路径 24 25 #define INFINITE 1000000 26 //打印答案 27 void print_ans(int n) 28 { 29 if (path[n] == 0) 30 { 31 printf("%s ", position[0][n]); 32 return ; 33 } 34 print_ans(path[n]); 35 printf("%s ", position[path[n] + 1][n]); 36 } 37 //dijkstra算法 38 void dijkstra() 39 { 40 int i,j; 41 42 path[0] = -1; 43 distance[0] = 0; 44 flag[0] = 1; 45 //初始化 46 for (i = 1; i < len_digital; i ++) 47 { 48 path[i] = 0; 49 if (position[0][i]) 50 { 51 distance[i] = 1; 52 } 53 else 54 { 55 distance[i] = INFINITE; 56 } 57 flag[i] = 0; 58 } 59 //查找最短路径 60 for (i = 1; i < len_digital; i ++) 61 { 62 int min = INFINITE,k; 63 for (j = 1; j < len_digital; j ++) { 64 if (!flag[j] && distance[j] < min) 65 { 66 min = distance[j]; 67 k = j; 68 } 69 } 70 if (min == INFINITE) 71 break; 72 flag[k] = 1; 73 //printf("%d : %d\n", k, distance[k]); 74 //松弛边 75 for (j = k + 1; j < len_digital; j ++) 76 { 77 if (!flag[j] && position[k + 1][j] && distance[k] + 1 < distance[j]) 78 { 79 distance[j] = distance[k] + 1; 80 path[j] = k; 81 } 82 } 83 } 84 } 85 //获得最长长度k 86 void computer_prefix_fuction(int prefix_func[]) 87 { 88 int k,q; 89 90 k = 0; 91 prefix_func[0] = 0; 92 q = 2; 93 while (temp_string[q - 1]) 94 { 95 while (k > 0 && temp_string[k] != temp_string[q - 1]) 96 k = prefix_func[k - 1]; 97 if (temp_string[k] == temp_string[q - 1]) 98 k ++; 99 prefix_func[q - 1] = k; 100 q ++; 101 } 102 } 103 //KMP算法 104 void kmp_matcher() 105 { 106 int q,i,prefix_func[51]; 107 108 computer_prefix_fuction(prefix_func); 109 i = 0;//计数 110 q = 0;//匹配的字符数 111 while (digital[i]) 112 { 113 while (q > 0 && temp_string[q] != digital[i]) 114 q = prefix_func[q - 1]; 115 if (temp_string[q] == digital[i]) 116 q ++; 117 if (! temp_string[q]) 118 { 119 //匹配成功 120 if (! position[i - q + 1][i]) 121 { 122 position[i - q + 1][i] = (char *)malloc(sizeof(char) * (q + 1)); 123 strcpy(position[i - q + 1][i], temp_input); 124 //printf("%s:%d ---> %d\n", temp_string, i - q + 1, i); 125 } 126 //匹配下一个 127 i = i - q + 1; 128 q = 0; 129 } 130 i ++; 131 } 132 } 133 int main(void) 134 { 135 int i,j; 136 137 while (1) 138 { 139 //输入数据 140 scanf("%s", digital); 141 if (digital[0] == '-') 142 break; 143 len_digital = strlen(digital); 144 scanf("%d", &n); 145 //初始化position表 146 for (i = 0; i < len_digital; i ++) 147 for (j = i; j < len_digital; j ++) 148 position[i][j] = NULL; 149 150 for (i = 0; i < n; i ++) 151 { 152 scanf("%s", temp_input); 153 j = 0; 154 while (temp_input[j]) 155 { 156 temp_string[j] = table[temp_input[j] - 'a']; 157 j ++; 158 } 159 temp_string[j] = 0; 160 //获得输入字符串在目标数字串的位置,并将其填入position表中 161 kmp_matcher(); 162 } 163 164 //使用dijkstra算法计算从位置0到位置n-1的最小跳数 165 dijkstra(); 166 if (distance[len_digital - 1] == INFINITE) 167 { 168 printf("No solution.\n"); 169 } 170 else 171 { 172 print_ans(len_digital - 1); 173 printf("\n"); 174 } 175 } 176 return 0; 177 }