步伐员的算法趣题Q14: 国名接龙

程序 程序 1801 人阅读 | 0 人回复

<
目录

1. 题目形貌
2. 解题分析--深度优先搜索
3. 代码
3.1 运行效果
4. 后记

1. 题目形貌

        FIFA天下杯对足球爱好者而言是四年一次的盛事。下面我们拿2014年天下杯参赛国的国名做个词语接龙游戏。不外,这里用的不是中文,而是英文字母(忽略巨细写)。2014年FIFA天下杯的32个参赛国参见代码中的国名列表。
        举个例子,如果像下面这样,那么连续 3 个国名之后接龙就结束了(因为以上国名列表中没有英文名称以 D 开头的国家)。
                 “Japan” →“Netherlands” →“Switzerland”
        题目:假设每个国名只能使用一次,求能连得最长的顺序,以及相应的国名个数。
2. 解题分析--深度优先搜索

        本题可以用深度优先搜索算法来解决。
        针对某个国家开始的情况,以深度搜索的方式搜索每一条可行的接龙路径。按照每条接龙路径一直搜索到底(直到当前接龙路径的最后一个国家再也找不到下一个可以接上的国家了)。此时将当前接龙的长度与保存的最大长度的接龙(在实现中可以作为全局变量)进行比力并根据比力效果相应更新。
        沿每条路径深度搜索时,用visitedunvisited分别管理已经搜索过的国家僧人未搜索过的国家。进一步的exploration仅从unvisited中选取下一个探索对象,因此省掉了“是否已被访问过”的检查判断,另一方面,visited是按照访问顺序存入被访问对象,所以其中存储的就是当前搜索的接龙顺序。visitedunvisited都需要以栈的方式进行管理,因此如果用递归调用的方式实现的话,将它们作为递归函数的接口参数通报即可;如果用循环方式实现的话,则需要注意显式的入栈和出栈管理。
        注意:本题是要求接龙中同一国名只能使用一次,这意味着路径不能形成loop。正因为这个,才可以以上述的visitedunvisited的方式进行分割以实现节点(每个国名就是一个节点)不重复访问的管理。在有些题目中,允许节点在路径上重复出现,但是不允许edge重复,则需要另外的防止重复访问的管理机制。
        别的,最长接龙搜索的效果依赖于从哪个国家开始,因此需要在针对以某个国家为起点的深度优先搜索的基础上再追加一层外层循环,遍历国家名字列表中的每一个国家作为起始国家分别进行接龙搜索。
3. 代码

  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on Mon Sep  6 08:17:34 2021
  4. @author: chenxy
  5. """
  6. import sys
  7. import time
  8. import datetime
  9. import math
  10. # import random
  11. from   typing import List
  12. # from   queue import Queue
  13. # from   collections import deque
  14. # import itertools as it
  15. country_list = ["Brazil", "Croatia", "Mexico",
  16.                 "Cameroon", "Spain", "Netherlands",
  17.                 "Chile", "Australia", "Colombia",
  18.                 "Greece", "Cote d&#39;Ivoire", "Japan",
  19.                 "Uruguay", "Costa Rica", "England",
  20.                 "Italy", "Switzerland", "Ecuador",
  21.                 "France", "Honduras", "Argentina",
  22.                 "Bosnia and Herzegovina", "Iran", "Nigeria",
  23.                 "Germany", "Portugal", "Ghana",
  24.                 "USA", "Belgium", "Algeria",
  25.                 "Russia", "Korea Republic" ]
  26. longest_jielong = []
  27. def jielong_explore(visited, unvisited):
  28.     """
  29.     Parameters
  30.     ----------
  31.     visited   : list of conuntry names already visited
  32.     unvisited : list of conuntry names not yet visited        
  33.     Returns   : None
  34.     """
  35.    
  36.     isNxtFound = False
  37.     if len(unvisited) != 0: # There are countries not yet visited, continue the exploration.
  38.         for index, c in enumerate(unvisited):
  39.             if c[0] == visited[-1][-1]:
  40.                 jielong_explore(visited + [c], unvisited[:index] + unvisited[index + 1:])
  41.                 # jielong_explore(visited.append(c), unvisited[:index] + unvisited[index + 1:])
  42.                 isNxtFound = True
  43.                
  44.     # If there is no next country found, then the current jielong path is finished,
  45.     # Compare the length of the current jielong with the recorded longgest jielong and update accordingly.
  46.     if not isNxtFound or len(unvisited) == 0:
  47.         global longest_jielong
  48.         if len(longest_jielong) < len(visited):
  49.             longest_jielong = visited
  50.    
  51. # Convert all country names to upper case for the convenience of processing.
  52. for k in range(len(country_list)):
  53.     country_list[k] = country_list[k].upper()
  54. # Start from each country for a new jielong game
  55. tStart = time.time()
  56. for i, country in enumerate(country_list):
  57.     jielong_explore([country], country_list[:i]+country_list[i+1:])
  58. tCost  = time.time() - tStart
  59. print("The max length of JieLong = {0}\n{1}\ntCost={2:6.3f}(sec)".format(len(longest_jielong), longest_jielong,tCost))
复制代码
3.1 运行效果

        The max length of JieLong = 8
        [&#39;KOREA REPUBLIC&#39;, &#39;CAMEROON&#39;, &#39;NETHERLANDS&#39;, &#39;SPAIN&#39;, &#39;NIGERIA&#39;, &#39;AUSTRALIA&#39;, &#39;ARGENTINA&#39;, &#39;ALGERIA&#39;]
        tCost= 0.002(sec)

4. 后记

        最长接龙题目,可以遐想到最长路径搜索题目,因此可以想到应该也可以用广度优先搜索(BFS)的方式来实现。但是BFS固然能够找出最长路径,因为不是沿着路径进行搜索,所以不能像DFS那样自然地记录搜索路径,在找到最长路径后,如何恢复出来对应的路径是一个题目。值得继续思考。

        上一篇:Q13: 满足字母算式的解法
        下一篇:Q15: 走楼梯
        本系列总目录参见:步伐员的算法趣题:详细分析和Python全解
        

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
1、本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明,如果原文没有版权声明,按照目前互联网开放的原则,我们将在不通知作者的情况下,转载文章;如果原文明确注明“禁止转载”,我们一定不会转载。如果我们转载的文章不符合作者的版权声明或者作者不想让我们转载您的文章的话,请您发送邮箱:Cdnjson@163.com提供相关证明,我们将积极配合您!
2、本网站转载文章仅为传播更多信息之目的,凡在本网站出现的信息,均仅供参考。本网站将尽力确保所提供信息的准确性及可靠性,但不保证信息的正确性和完整性,且不对因信息的不正确或遗漏导致的任何损失或损害承担责任。
3、任何透过本网站网页而链接及得到的资讯、产品及服务,本网站概不负责,亦不负任何法律责任。
4、本网站所刊发、转载的文章,其版权均归原作者所有,如其他媒体、网站或个人从本网下载使用,请在转载有关文章时务必尊重该文章的著作权,保留本网注明的“稿件来源”,并自负版权等法律责任。
回复 关闭延时

使用道具 举报

 
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则