zoukankan      html  css  js  c++  java
  • 【6.12校内test】T1单词序列

    【问题描述】

           给出两个单词(开始单词和结束单词)以及一个词典。找出从开始单词转换到结束单词, 所需要的最短转换序列。转换的规则如下:

    1、每次只能改变一个字母

    2、转换过程中出现的单词(除开始单词和结束单词)必须存在于词典中

    例如: 开始单词为:hit

    结束单词为:cog

    词典为:[hot,dot,dog,lot,log,mot]

    那么一种可能的最短变换是: hit -> hot -> dot -> dog -> cog,

    所以返回的结果是序列的长度 5;

    注意: 1、如果不能找到这种变换,则输出 0;

    2、词典中所有单词长度一样;

    3、所有的单词都由小写字母构成;

    4、开始单词和结束单词可以不在词典中。

    【输入文件】

             共两行,第一行为开始单词和结束单词(两个单词不同),以空格分开。第二行为若干 的单词(各不相同),以空格分隔开来,表示词典。单词长度不超过 5,单词个数不超过 30。

    【输出文件】

           输出转换序列的长度。

    【输入样例】

    hit cog

    hot dot dog lot log

    【输出样例】

    5

    【数据范围】

    单词长度不超过5,单词个数不超过30;


    这个题算法大概是搜索,这可真的是令人质壁分离。

    还记得我烤鸡写了一个多小时呀qwq(果真还是我太菜了),感觉自己代码能力真心不好呀,我可能也就for写的足够优秀了emmm。

    (滚去写这个题代码了)

    MY SOLUYION:
    first.这个题读入就很卡人,下面我们来总结一下输入若干个(题目未给出具体的数值)应该肿么写:

    1. 输入一串长度不定的字符串
      string a;
      cin>>a;//直接用string然后cin或scanf输入就好;
    2. 今天用到的(我的写法)(自我感觉良好)
      while(ch!='
      '){
              n++;
              scanf("%s",dic[n].g);
              ch=getchar();
          }//因为输入时两个字符串之间会间隔一个空格,因此我们getchar()掉这个空格,getchar的这个空格记为ch,当ch='
      '(即说明读到了回车),那么很显然的,就不应该读下去了
    3. 之前sy讲得:(感觉我们的是差不多的嘞qwq)
      char bj=' ',i=1;//bj即为标记,i为数组下标(多个数用数组比较方便)
        while(bj==' ')//因为输完数要按空格
        {cin>>a[++i];
        bj=getchar();
       
      一行内输入n个整数
    4. 神仙们的写法:
      //楼下捕捉一只yjk神仙
      while(cin>>s[++n]);
      //好像神仙们都是这么写的,就我这种蒟蒻写的这么复杂emm

    然后因为方便计算,我把str和end加入了这n个单词之后,在字典有的单词的基础上+2

    //输入部分
    scanf("%s",str);
        scanf("%s",end);
        len=strlen(str);
        while(ch!='
    '){
            n++;
            scanf("%s",dic[n].g);
            ch=getchar();
        }
        for(int i=0;i<len;i++) dic[n+1].g[i]=str[i],dic[n+2].g[i]=end[i];
        n+=2;ss=n-1;ee=n;

    next.因为数据比较小嘛,所以我的想法是开一个二维数组cy(chayi)[i][j],表示第i个单词与第j个单词的差异,然后大概应该可能是用dfs计算,然后出结果;对于预处理:

    • 因为每个单词长度都不超过5,所以直接爆扫就可以了;为了看着比较简洁好看,我们写一个bj(比较)函数;二重循环(为了减少时间,我们可以把j从i+1开始循环,然后双向存储) 注意:cy[i][i]=0;(其实这个倒是也不重要因为dfs时会忽略i==j的情况)
    • 对于bj函数,返回的是第i个单词与第j个单词相差的字母数量;
      //比较函数与预处理
      int bj(char a[],char b[]){
          int c=0;
          for(int i=0;i<len;i++)
            if(a[i]!=b[i]) c++;
          return c;
      }
      ……
      
      for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
               cy[j][i]=cy[i][j]=bj(dic[i].g,dic[j].g),cy[i][i]=0;

    end.代码的核心dfs部分:

    1. 定义两个变量进行dfs:begin/*表示从哪个单词开始搜索下一个单词*/,ans/*记录进行了几次变换*/
    2. 在主程序中dfs(ss/*表示起点的编号*/,1/*由样例可知,str与end也要算在内,因此从1开始*/
    3. 先是临界条件:当当前dfs到的编号刚好是end的标号ee时,用f数组记录下这个解(显然dfs会搜索出所有转化情况,而我们只取最小的一种,因此要把每一种记录下来,最后sort求解)return 1(对于这个return 1是用来判断是否有解的)
    4. vis数组,用来判断某一个点是否已经搜索过
    5. 定义一个next,利用for循环找到一个与begin的差异只有1的点[如果没有显然这种情况不成立,也就是无解,因此定义一个bj=0,如果找到了差异是1的点,bj=1,在dfs的最后,如果bj=0,就说明无解,返回0],令next=i;标记vis[next]为已经搜索(1);bj=1;然后搜索(next,ans+1);记得回溯使vis[next]=0;

    以上就是大致算法流程。

    CODE:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<string>
    
    using namespace std;
    
    char str[5],end[5],ch;
    struct node1{
        char g[5];
    }dic[31];
    int n,cy[35][35],len,ss,ee,ans,f[100],cnt;
    
    int bj(char a[],char b[]){
        int c=0;
        for(int i=0;i<len;i++)
          if(a[i]!=b[i]) c++;
        return c;
    }
    bool vis[31];
    
    int solve(int begin,int ans){
        if(begin==ee) {
            f[++cnt]=ans;
            return 1;
        }
        int next;
        int bj=0;
        for(int i=1;i<=n;i++){
            if(vis[i]) continue;
            if(i==begin) continue;
            if(cy[begin][i]!=1) continue;
            
               next=i;vis[next]=1;
               bj=1;
               solve(next,ans+1);
               vis[next]=0;
        }
        if(!bj) return 0;
    }
    
    int main(){
    //    freopen("word2.in","r",stdin);
    //    freopen("word.out","w",stdout);
        scanf("%s",str);
        scanf("%s",end);
        len=strlen(str);
        while(ch!='
    '){
            n++;
            scanf("%s",dic[n].g);
            ch=getchar();
        }
        for(int i=0;i<len;i++) dic[n+1].g[i]=str[i],dic[n+2].g[i]=end[i];
        n+=2;ss=n-1;ee=n;
        for(int i=1;i<=n;i++)
          for(int j=i+1;j<=n;j++)
             cy[j][i]=cy[i][j]=bj(dic[i].g,dic[j].g),cy[i][i]=0;
        vis[ss]=1;
        if(solve(ss,1)==0)cout<<"0"<<endl;
        else{
            sort(f+1,f+cnt+1);
            cout<<f[1]<<endl;
        }
        return 0;
    }

    然后我们看一下标程:

    CODE:

    //加一句注释提醒自己并不想看标程,改天再看吧qwq
    #include<cstdio> #include<iostream> #include<queue> #include<cstring> using namespace std; struct node{ string s; int dep; }; queue<node>q; string ss,st,s[31]; int vis[31]; int n=0; int can(string s,string t){ if(s.size()!=t.size()) return 0; int c=0; for(int i=0;i<s.size();i++) if(s[i]!=t[i]) c++; return c==1; } int bfs(){ memset(vis,0,sizeof(vis)); q.push((node){ss,1}); while(!q.empty()){ node cur=q.front();q.pop(); if(cur.s==st) return cur.dep;//是目标 if(can(cur.s,st)) return cur.dep+1;//再一步就是目标 for(int i=0;i<n;i++) if(!vis[i]&&can(cur.s,s[i])){ q.push((node){s[i],cur.dep+1}); vis[i]=1; } } return 0; } int main(){ freopen("word.in","r",stdin); freopen("word.out","w",stdout); cin>>ss>>st; while(cin>>s[n++]); cout<<bfs()<<endl; return 0; }

    end-

  • 相关阅读:
    经典测试面试题
    virsh命令来创建虚拟机
    软件开发模式对比(瀑布、迭代、螺旋、敏捷)
    软件测试 --工作内容
    使用WCF进行跨平台开发之一(WCF的实现、控制台托管与.net平台的调用)
    【开源分享:入门到精通ASP.NET MVC+EF6+Bootstrap】从这里开始,一起搭框架(1)开篇介绍
    开源:ASP.NET MVC+EF6+Bootstrap开发框架
    Quartz.Net 使用
    基于.NET平台常用的框架整理
    .NET中Redis安装部署及使用方法简介
  • 原文地址:https://www.cnblogs.com/zhuier-xquan/p/11010045.html
Copyright © 2011-2022 走看看