通过单字符置换可以将一个单词改为另一个单词

问题:假设存在一个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;
}

测试用例:

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值