问题:假设存在一个5字母单词的字典。给出一个算法确定单词A是否可以通过一系列的单字符置换转换为单词B,并且如果可以的话,输出相应的单词序列。例如,bleed通过序列bleed、blend、blond、blood转换为blood。
求解思路:
将任意单词抽象为节点,任意两个单词之间可以通过变换一个字母到达的变换可以抽象为图中两个节点是相连通的,而不能仅通过替换一个字母变换就到达终点的两个节点之间是不连通的,问题变为如果任意两个单词之间存在可行解,意味着图中两个单词是连通的。我们发现,寻找两个节点的通路就能找到一种解法。
所以可以查找图中两个节点之间的最短路径,用Floyd算法进行求解,Floyd算法直接给出了所有节点之间的最短路径。若不存在路径的情况,即两个节点之间没有可达的路径,则这两个节点必定存在不同的连通分支中,意味着字典中的词是存在着至少两个连通分支的。
//单词转换
#include <stdio.h>
#include <string.h>
#define LENGTH 6
#define NUM 23
#define MAX 100
typedef struct DataType
{
int MAP[NUM][NUM]; //定义一个二维数组MAP
int a[NUM][NUM];
int path[NUM][NUM];
}SeqList;
char dic[NUM][LENGTH]= {"bland","blank","bleak","bleed","blend","blind","blink","blond",
"blood","bloom","blown","blows","brand","brank","bread","break","bream","breed","brown",
"clank","clink","dread","dream"};
bool edge_test(char source[],char target[]);
int main()
{
SeqList L;
for(int i = 0;i < NUM;i++){
for(int j = 0;j < NUM;j++){
if(true == edge_test(dic[i],dic[j])){
L.MAP[i][j] = 1;
}
else if(i != j){
L.MAP[i][j] = MAX;
}
else
L.MAP[i][j] = 0;
}
}
//Floyd算法求最短路径
int j,k,n = NUM;
for(int i = 0;i < n; i++){
for(int j=0; j<n; j++){
L.a[i][j] = L.MAP[i][j];
if(i != j && L.a[i][j] < MAX){
L.path[i][j] = i;
}
else{
L.path[i][j] = 0;
}
}
}
for(k = 0;k < n;k++){
for(int i = 0;i < n;i++){
for(int j = 0;j < n;j++){
if(L.a[i][k] + L.a[k][j] < L.a[i][j]){
L.a[i][j] = L.a[i][k] + L.a[k][j];
L.path[i][j] = L.path[k][j];
}
}
}
}
char source[NUM],target[NUM];
printf("请输入要被转换的字符:\n");
scanf("%s",source);
printf("请输入转换得到的字符:\n");
scanf("%s",target);
int indexs = -1;
int indext = -1;
for(int i = 0;i < NUM;i++){
if(strcmp(source,dic[i]) == 0){
indext = i;
}
if(strcmp(target,dic[i]) == 0){
indexs = i;
}
}
int x = L.path[indexs][indext];
bool exist = false;
if(indexs == x){
if(true == edge_test(dic[indext],dic[indexs])){
printf("%s->",dic[indext]);
printf("%s\n",dic[indexs]);
}
}
else if(indexs == L.path[indexs][x]){
printf("%s->",dic[indext]);
printf("%s->",dic[x]);
printf("%s\n",dic[indexs]);
}
else{
while(true){
if(indexs != L.path[indexs][x]){
int y = L.path[indexs][x];
if(x == y){
printf("不存在变换系列\n");
exist=false;
break;
}
else{
if(!exist){
printf("%s->",dic[indext]);
printf("%s->",dic[x]);
}
exist = true;
}
x = y;
}
else{
exist = true;
break;
}
if(exist){
printf("%s->",dic[x]);
}
}
if(exist){
printf("%s\n",dic[indexs]);
}
}
return 0;
}
bool edge_test(char source[],char target[])//
{
int tag[LENGTH-1];
for(int i = 0; i < LENGTH-1; i++){
if(source[i] != target[i]){
tag[i] = 1;
}
else{
tag[i] = 0;
}
}
int sum = 0;
for(int i = 0; i < LENGTH-1; i++)
sum += tag[i];
if(sum == 1){
return true;
}
else
return false;
}
测试用例: