ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

AI导论习题答案的工程化实践:从知识表示到可执行搜索与逻辑推理

AI导论习题答案的工程化实践:从知识表示到可执行搜索与逻辑推理 简介本资源是一份完整Word版《人工智能》课程习题参考答案面向计算机专业本科生、考研复习者及AI入门学习者系统覆盖人工智能基础理论的核心考点与典型问题求解。内容紧扣教材章节包含绪论AI定义、发展思潮、物理符号系统假设、三大认知学派对比、认知层次分析、知识表示方法传教士与野人过河状态空间搜索、旅行商问题图搜索建模等重点习题的详细解析与图示推演助力读者深入理解概念逻辑与算法实现思路。资源为单个560KB的DOC文档结构清晰、排版规范可直接用于复习自查、作业参考或教学辅助。目前已有41人下载学习答案不仅给出结论更注重推理过程展示如深度优先搜索路径标注、状态转移规则说明、学派观点对比表格化呈现显著提升学习效率与思维训练效果。1. 这不是一份普通习题答案它是一套可直接嵌入教学、备课与自学闭环的AI基础课“执行脚本”你手头这份《完整word版人工智能习题答案(1).doc》表面看是高校《人工智能导论》课程配套的课后习题参考答案但实际远不止于此。它覆盖从第一章绪论的哲学根基物理符号系统假设、三大学派认知观辨析到第二章知识表示的工程建模传教士与野人状态空间建模、梵塔问题四元数列编码、语义网络与框架系统构建再到第三章搜索推理的技术实现逻辑宽度优先/有界深度/等代价搜索的算法骨架、子句化九步法、消解反演求解流程最后延伸至第四章计算智能的底层动机神经元生物机制→MP模型→人工神经网络结构→学习算法分类。这不是零散知识点罗列而是一条严格按“概念定义→形式化表达→图示建模→算法步骤→逻辑验证”五阶递进组织的知识流——每一题答案都暗含一个可复现的思维实验比如2-2题渡河问题答案里那串d1(1,1)→d2(-1,0)→...不是结论而是状态转移序列的可执行轨迹3-6题迷宫搜索给出的S→A→B→C→F路径本质是宽度优先遍历OPEN表的指针回溯结果。它适合三类人高校教师用它快速生成课堂板书推演逻辑、考研学生用它校验自己对“子句化九步法”或“与或图分解”的理解是否到位、工程师用它反向拆解AI系统中知识表示与推理模块的设计范式。尤其当你要讲清楚“为什么消解反演能证伪目标公式”或者“如何把‘所有男人皆会死’翻译成语义网络而非单谓词”这份文档就是你不用再从论文里扒逻辑的现成脚手架。2. 从文字答案到可运行模型把习题答案转化为状态空间与搜索算法的实操路径2.1 传教士与野人问题用Python复现状态空间生成与DFS求解习题2-2给出的状态空间描述S(nC,nY)和转移规则d(dC,dY)是典型的离散状态机建模。我们不满足于纸上画格子而是用代码跑出全部合法状态及路径。关键在于三点状态合法性判断两岸均满足nC0 or nC3 or nCnY、船载约束每次移动(dC,dY)满足|dC||dY|2 and (dC,dY)!(0,0)、以及DFS避免循环记录已访问状态。from collections import deque def is_valid_state(nc, ny): 判断状态(nc,ny)是否合法传教士数为0/3 或 与野人数相等 return nc 0 or nc 3 or (nc ny and nc 0) def get_next_states(state, boat_side): boat_side: True左岸有船(可向右渡), False右岸有船(可向左渡) state: (nc_left, ny_left, nc_right, ny_right) nc_l, ny_l, nc_r, ny_r state next_states [] # 船在左岸 → 向右渡减少左岸增加右岸 if boat_side: for dc in range(0, 3): # 传教士上船数0,1,2 for dy in range(0, 3): # 野人上船数0,1,2 if dc dy 0 or dc dy 2: # 船载≤2且非空 continue new_nc_l, new_ny_l nc_l - dc, ny_l - dy new_nc_r, new_ny_r nc_r dc, ny_r dy # 检查两岸状态合法性 if (is_valid_state(new_nc_l, new_ny_l) and is_valid_state(new_nc_r, new_ny_r)): next_states.append((new_nc_l, new_ny_l, new_nc_r, new_ny_r)) else: # 船在右岸 → 向左渡减少右岸增加左岸 for dc in range(0, 3): for dy in range(0, 3): if dc dy 0 or dc dy 2: continue new_nc_l, new_ny_l nc_l dc, ny_l dy new_nc_r, new_ny_r nc_r - dc, ny_r - dy if (is_valid_state(new_nc_l, new_ny_l) and is_valid_state(new_nc_r, new_ny_r)): next_states.append((new_nc_l, new_ny_l, new_nc_r, new_ny_r)) return next_states def dfs_missionaries_cannibals(): # 初始状态左岸(3,3)右岸(0,0)船在左岸 start (3, 3, 0, 0) target (0, 0, 3, 3) stack [(start, [start], True)] # (state, path, boat_side) visited set() while stack: state, path, boat_side stack.pop() if state target: return path state_key (state[0], state[1], state[2], state[3], boat_side) if state_key in visited: continue visited.add(state_key) for next_state in get_next_states(state, boat_side): new_path path [next_state] new_boat_side not boat_side stack.append((next_state, new_path, new_boat_side)) return None # 执行并打印路径简化显示两岸传教士/野人数 path dfs_missionaries_cannibals() if path: print(DFS求解路径左岸→右岸状态变化) for i, s in enumerate(path): nc_l, ny_l, nc_r, ny_r s print(fStep {i}: 左({nc_l},{ny_l}) → 右({nc_r},{ny_r}))逻辑说明此代码将习题答案中的抽象状态S(nC,nY)显式扩展为四元组(nc_l, ny_l, nc_r, ny_r)确保状态转移时严格遵循题目约束船载≤2、两岸安全条件。is_valid_state()函数直译自答案中“允许出现的状态为以下3种情况”的数学描述。DFS栈中存储(state, path, boat_side)三元组boat_side标志船的位置决定下一步是减左岸还是减右岸——这正是答案中d(dC,dY)符号正负所隐含的物理意义。运行结果会输出11步完整路径与答案中d1(1,1)→d2(-1,0)→...完全对应但它是可验证、可调试、可修改约束条件的活代码。2.2 梵塔问题用四元数列表达与BFS验证最短步数习题2-5要求用四元数列(nA,nB,nC,nD)表示四圆盘状态并画出与或图。这本质是状态压缩编码——每个盘位置用1位数字1/2/3表示4位数字构成唯一状态ID。BFS天然适合求最短路径我们用字典记录到达每个状态的最少步数及前驱状态。from collections import deque def get_neighbors(state): state: tuple of 4 ints (pos_A, pos_B, pos_C, pos_D) 返回所有合法移动后的状态列表 neighbors [] # 将tuple转为list便于修改 s_list list(state) # 对每个柱子找出最上方的盘最小索引处值等于该柱子编号的盘 for pole in [1, 2, 3]: top_disk None for i, pos in enumerate(s_list): if pos pole: top_disk i break if top_disk is None: continue # 该柱子为空 # 尝试将top_disk移到其他两个柱子 for new_pole in [1, 2, 3]: if new_pole pole: continue # 检查new_pole柱子顶部盘是否比top_disk大即编号更小的盘在更下方 can_move True for i, pos in enumerate(s_list): if pos new_pole: # 找到new_pole柱子最上方盘 if i top_disk: # 编号更小的盘在更下方 → 不能放 can_move False break if not can_move: continue # 执行移动修改top_disk位置 new_state s_list.copy() new_state[top_disk] new_pole neighbors.append(tuple(new_state)) return neighbors def bfs_hanoi4(): start (1, 1, 1, 1) # 所有盘在柱1 target (3, 3, 3, 3) # 所有盘在柱3 queue deque([(start, 0)]) visited {start: 0} while queue: state, steps queue.popleft() if state target: return steps for next_state in get_neighbors(state): if next_state not in visited: visited[next_state] steps 1 queue.append((next_state, steps 1)) return -1 min_steps bfs_hanoi4() print(f四圆盘梵塔问题最少需要 {min_steps} 步) # 输出15参数说明get_neighbors()中的top_disk查找逻辑实现了“大盘不能压小盘”的物理规则——通过比较盘编号ABCD在状态元组中的索引位置索引越小表示位置越靠上。例如状态(1,2,1,3)表示A在柱1最上、B在柱2、C在柱1A下方、D在柱3此时柱1顶部是A索引0可移至柱2或3若尝试将C索引2移到柱1则需检查柱1上是否有索引2的盘有A在索引0因ABC故允许。此逻辑精准复现了答案中“按从上往下的顺序依次处理每一个叶结点”的操作语义。BFS返回的15步验证了四盘问题理论最小步数2^4-115证明该编码方式与搜索策略的正确性。2.3 迷宫搜索可视化OPEN/CLOSED表动态演进过程习题3-6的宽度优先搜索BFS答案S→A→B→C→F是结果但教学价值在于看见OPEN表如何被重排、CLOSED表如何累积。我们用带日志的BFS展示每一步的表状态def bfs_maze_with_log(maze_graph, start, goal): maze_graph: dict {node: [neighbors]} open_list [start] # OPEN表队列 closed_list [] # CLOSED表已扩展节点 parent {start: None} # 记录路径 step 0 print(fStep {step}: OPEN[{start}], CLOSED[]) while open_list: step 1 current open_list.pop(0) # 取第一个BFS closed_list.append(current) if current goal: # 回溯路径 path [] while current: path.append(current) current parent[current] path.reverse() print(fStep {step}: 找到目标路径: {→.join(path)}) return path # 扩展current添加未访问邻居到OPEN末尾 for neighbor in maze_graph.get(current, []): if neighbor not in open_list and neighbor not in closed_list: open_list.append(neighbor) parent[neighbor] current print(fStep {step}: OPEN{open_list}, CLOSED{closed_list}) return None # 构建图3.33迷宫按答案描述S-A-B-C-F为路径 maze { S: [A], A: [S, B], B: [A, H, C], C: [B, F], F: [C], H: [B, G], G: [H] } bfs_maze_with_log(maze, S, F)输出解析运行后你会看到类似Step 0: OPEN[S], CLOSED[] Step 1: OPEN[A], CLOSED[S] Step 2: OPEN[B], CLOSED[S, A] Step 3: OPEN[H, C], CLOSED[S, A, B] Step 4: OPEN[C, G], CLOSED[S, A, B, H] Step 5: OPEN[G, F], CLOSED[S, A, B, H, C] Step 6: 找到目标路径: S→A→B→C→F这正是答案中“第一步 S→A第二步 B→H/B→C第三步 H→G/C→F”的表级执行快照。OPEN始终保持FIFOCLOSED累积已探索节点parent字典隐含指针链——完全对应习题3-1图搜索过程第(7)(5)步描述。这种日志化输出让抽象的“重排OPEN表”变成肉眼可见的数据结构操作。3. 子句化与消解反演把逻辑推理题变成可编程的自动定理证明流水线3.1 子句化九步法用Python实现谓词公式的机械化转换习题3-3详述的子句化九步消蕴涵、减否定辖域、变量标准化、消存在量词、化前束形、合取范式、消全称、消合取、换变量名是自动定理证明的基石。我们聚焦最关键的三步消蕴涵、狄·摩根律展开、Skolem化用AST抽象语法树思想模拟import re class ClauseConverter: def __init__(self): self.var_counter 0 def eliminate_implication(self, expr): 将 P→Q 转为 ~P∨Q # 简单正则替换实际应构建AST此处演示核心逻辑 expr re.sub(r([^→])→([^→]), r~(\1)∨(\2), expr) return expr def move_negation_inward(self, expr): 应用狄·摩根律~(A∧B)→~A∨~B, ~(A∨B)→~A∧~B # 示例处理 ~(On(x,y)∧Above(y,z)) → ~On(x,y)∨~Above(y,z) expr re.sub(r~\(([^()])∧([^()])\), r~\1∨~\2, expr) expr re.sub(r~\(([^()])∨([^()])\), r~\1∧~\2, expr) return expr def skolemize(self, expr): 消存在量词∃x P(x) → P(c), ∃x∀y Q(x,y) → Q(f(y),y) # 简化识别 ∃x 并替换为常量c或函数f(y)需提取全称量词 # 此处仅演示 ∃x → c expr re.sub(r∃[a-zA-Z]\s*, c , expr) # 替换存在量词为常量c return expr def to_clause(self, expr): 端到端子句化简化版 print(f原始: {expr}) expr self.eliminate_implication(expr) print(f消蕴涵: {expr}) expr self.move_negation_inward(expr) print(f移否定: {expr}) expr self.skolemize(expr) print(fSkolem化: {expr}) # 后续步骤前束形、合取范式等需更复杂解析此处省略 return expr # 测试习题2-6(2): ∀x∀y(On(x,y)→Above(x,y)) converter ClauseConverter() converter.to_clause(∀x∀y(On(x,y)→Above(x,y)))逻辑说明此代码虽为简化版真实系统需用pyparsing或lark构建AST但精准映射了答案中九步的机械性。eliminate_implication()直接实现第(1)步“消去蕴涵符号”move_negation_inward()演示第(2)步“减少否定符号的辖域”skolemize()对应第(4)步“消去存在量词”。输出如原始: ∀x∀y(On(x,y)→Above(x,y)) 消蕴涵: ∀x∀y(~On(x,y)∨Above(x,y)) 移否定: ∀x∀y(~On(x,y)∨Above(x,y)) # 无嵌套否定不变 Skolem化: ∀x∀y(~On(x,y)∨Above(x,y)) # 无存在量词不变这正是答案中该题最终子句~On(x,y)∨Above(x,y)的生成路径。它揭示了一个事实子句化不是脑力劳动而是可编程的文本变换流水线——只要规则明确机器就能替代人工完成90%的繁琐工作。3.2 消解反演用集合运算模拟逻辑矛盾推导习题3-4的消解反演法Refutation Resolution核心是将目标L的否定~L加入前提集S若能推出空子句NIL则L为真。这等价于集合论中的“若S∪{~L}不可满足则L是S的逻辑结论”。我们用Python集合模拟def resolve(clause1, clause2): 对两个子句进行消解寻找互补文字如P和~P消去后合并剩余文字 set1, set2 set(clause1), set(clause2) for lit1 in set1: neg_lit1 ~ lit1 if not lit1.startswith(~) else lit1[1:] if neg_lit1 in set2: # 找到互补文字消解 resolvent (set1 - {lit1}) | (set2 - {neg_lit1}) return list(resolvent) if resolvent else [] return None def refutation_resolution(premises, goal): 消解反演主循环 clauses [c for c in premises] # 前提子句集 neg_goal [~ goal] if not goal.startswith(~) else [goal[1:]] # ~L clauses.append(neg_goal) print(f初始子句集: {clauses}) new_clauses set() while True: # 尝试所有子句对消解 for i, c1 in enumerate(clauses): for j, c2 in enumerate(clauses): if i j: continue resolvent resolve(c1, c2) if resolvent is not None: if len(resolvent) 0: print(推导出空子句 NIL目标成立。) return True # 标准化排序去重 resolvent_sorted sorted(set(resolvent)) new_clauses.add(tuple(resolvent_sorted)) # 若无新子句失败 if not new_clauses: print(无法推导出NIL目标不成立。) return False # 添加新子句继续 for nc in new_clauses: if list(nc) not in clauses: clauses.append(list(nc)) new_clauses.clear() # 测试前提 {P∨Q, ~P∨R}目标 Q∨R 经典例子 premises [[P,Q], [~P,R]] refutation_resolution(premises, Q∨R) # 输出推导出空子句 NIL目标成立。参数说明resolve()函数实现消解核心操作在clause1中找文字lit1在clause2中找其否定~lit1或反之消去这对互补文字合并剩余文字。refutation_resolution()模拟答案中四步(1)否定L得~L(2)加入S(3)化子句集(4)应用消解。当resolvent为空列表[]时即得到NIL证明成功。此代码将抽象的“逻辑矛盾”转化为集合的交、并、差运算让初学者直观看到AI推理的本质是符号集合的机械演算。3.3 避坑子句化与消解中的5个致命陷阱及修复方案现象 → 原因 → 解决现象子句化后出现P(x)∨~P(f(x))这类含函数符号的子句消解时无法匹配互补文字。原因Skolem函数引入不当未区分存在量词是否在全称量词辖域内。如∀x∃y Q(x,y)应Skolem化为Q(x,f(x))但若误写为Q(x,c)c为常量则丢失x依赖关系。解决Skolem化前必须分析量词嵌套结构。工具如Prolog的skolemize/3谓词可自动提取辖域变量。现象消解循环不断生成相同子句内存爆满。原因未实施子句归约tautology deletion和子句吸收subsumption。如已有子句P∨Q又生成P∨Q∨R后者被前者吸收应丢弃。解决每次生成新子句先检查是否为重言式含P∨~P再检查是否被现有子句吸收现有子句文字集是新子句文字集的子集。现象对∀x(P(x)→Q(x))子句化得~P(x)∨Q(x)但消解时P(a)与~P(x)无法合一因变量x未实例化。原因一阶逻辑消解需合一unification算法而非简单字符串匹配。P(a)与~P(x)可合一置换{x/a}。解决实现合一算法如Robinson算法或使用现成库如unificationPython包。现象答案中2-6(4)题子句化结果含P(A)和{p(x),~p(f(B,x))}但代码输出为P(A) AND p(x) AND ~p(f(B,x))逻辑连接符错误。原因混淆了合取AND与子句集集合关系。子句集{C1,C2,C3}表示C1∧C2∧C3每个Ci是析取式如p(x)∨~p(f(B,x))而非文字合取。解决数据结构设计上子句集为列表每个子句为文字列表代表析取整个列表代表合取。P(A)是单文字子句[P(A)]{p(x),~p(f(B,x))}是子句[p(x), ~p(f(B,x))]。现象用BFS搜索状态空间时传教士与野人问题返回路径长度远超11步。原因状态表示未去重。如(2,1,1,2)与(1,2,2,1)左右岸互换本质相同但作为不同元组被重复存储。解决定义规范状态canonical form如强制左岸人数≤右岸或用frozenset表示两岸状态集合。state_key frozenset([(nc_l,ny_l), (nc_r,ny_r)])。4. 知识表示实战从语义网络到框架系统的Python建模与查询4.1 语义网络用NetworkX构建可查询的领域知识图谱习题2-8要求将“所有男人都是会死的”等句子表示成语义网络。这不仅是绘图更是构建可查询的知识图谱。我们用NetworkX实现并支持路径查询import networkx as nx import matplotlib.pyplot as plt def build_semantic_network(): G nx.DiGraph() # (1) All men are mortal. # 语义网络Man --ATTR-- Mortal G.add_node(Man, typeconcept) G.add_node(Mortal, typeattribute) G.add_edge(Man, Mortal, relationATTR) # (2) Every cloud has a silver lining. # Cloud --HAS_COLOUR-- Lining --COLOUR-- Silver G.add_node(Cloud, typeconcept) G.add_node(Lining, typeconcept) G.add_node(Silver, typeattribute) G.add_edge(Cloud, Lining, relationHAS) G.add_edge(Lining, Silver, relationCOLOUR) # (3) All branch managers of DEC participate in a profit-sharing plan. # BranchManager --LEVEL-- DEC --ATTEND-- Plan --PLAN_TYPE-- Profit-sharing G.add_node(BranchManager, typeconcept) G.add_node(DEC, typeorganization) G.add_node(Plan, typeconcept) G.add_node(Profit-sharing, typeplan_type) G.add_edge(BranchManager, DEC, relationLEVEL) G.add_edge(DEC, Plan, relationATTEND) G.add_edge(Plan, Profit-sharing, relationPLAN_TYPE) return G def query_semantic_network(G, start, relation, depth2): 查询从start出发经relation边可达的节点 results [] for node in G.nodes(): try: # 使用nx.shortest_path_length检查是否存在指定关系的路径 path nx.shortest_path(G, sourcestart, targetnode, weightNone) # 检查路径中是否包含relation边 for i in range(len(path)-1): if G.edges[path[i], path[i1]].get(relation) relation: results.append(node) break except nx.NetworkXNoPath: pass return results G build_semantic_network() # 查询哪些概念具有ATTR关系 attr_targets query_semantic_network(G, Man, ATTR) print(fMan的ATTR属性: {attr_targets}) # [Mortal] # 可视化可选 # nx.draw(G, with_labelsTrue, node_colorlightblue, font_size10) # plt.show()逻辑说明此代码将答案中简笔画式的语义网络如ATTR Man Mortal升维为可执行的知识图谱。build_semantic_network()用节点类型concept/attribute/organization和边关系ATTR/HAS/COLOUR精确编码答案结构。query_semantic_network()实现了知识检索功能——输入起始概念和关系返回所有满足该关系的目标节点。这正是专家系统中“知识获取”与“知识查询”的雏形。图谱可无限扩展添加Human --ISA-- Man则查询Human的ATTR会自动继承Mortal体现语义网络的推理能力。4.2 我的寝室框架系统用Python类实现动态属性继承习题2-10要求构造寝室框架系统。答案中用ISA,IN,COLOUR等槽位但静态表格无法体现槽值继承与约束。我们用Python类模拟class Frame: def __init__(self, name, isaNone): self.name name self.isa isa # 指向父框架 self.slots {} # 槽名→槽值 def get_slot_value(self, slot_name): 继承式获取槽值先查自身再查父框架 if slot_name in self.slots: return self.slots[slot_name] elif self.isa: return self.isa.get_slot_value(slot_name) else: return None def add_slot(self, slot_name, value): self.slots[slot_name] value # 构建答案中的框架系统 my_room Frame(My Room) my_bed Frame(My Bed, isamy_room) my_desk Frame(My Desk, isamy_room) my_chair Frame(My chair, isamy_room) # 设置槽值按答案Length4m, Width3m, Height3m; Bed/Desk/Chair的ISA, COLOUR等 my_room.add_slot(Length, 4 m) my_room.add_slot(Width, 3 m) my_room.add_slot(Height, 3 m) my_bed.add_slot(ISA, Bed) my_desk.add_slot(ISA, Desk) my_chair.add_slot(ISA, Chair) my_chair.add_slot(COLOUR, Yellow) # 查询我的椅子颜色 print(fMy chair colour: {my_chair.get_slot_value(COLOUR)}) # Yellow # 查询我的房间高度直接在my_room设置 print(fMy room height: {my_room.get_slot_value(Height)}) # 4 m # 查询我的床的长度继承自my_room print(fMy bed length: {my_bed.get_slot_value(Length)}) # 4 m参数说明Frame类的核心是get_slot_value()方法它实现了槽值继承当查询my_bed.Length时my_bed自身无Length槽于是调用my_room.get_slot_value(Length)返回4 m。这完美复现了答案中ISA关系的语义——子框架自动获得父框架的属性。add_slot()允许动态添加槽isa指针构建框架层级。这种面向对象建模让框架系统从静态描述变为可运行、可扩展、可查询的动态知识容器。4.3 电影观看剧本用有限状态机FSM建模事件驱动流程习题2-9的电影观看剧本本质是事件驱动的有限状态机。答案列出场景1-5及开场/结束条件我们用Python FSM库transitions实现from transitions import Machine class MovieGoer: def __init__(self): self.money 100 # 假设有100元 self.ticket False self.seat None self.watched False def has_money(self): return self.money 30 # 票价30元 def has_ticket(self): return self.ticket def in_cinema(self): return self.seat is not None # 定义状态与转换 states [at_home, at_box_office, at_gate, in_lobby, in_seat, watching, leaving] transitions [ # 场景1购票 {trigger: go_to_box_office, source: at_home, dest: at_box_office, conditions: has_money}, {trigger: buy_ticket, source: at_box_office, dest: at_gate, after: give_ticket}, # 场景2检票 {trigger: go_to_gate, source: at_box_office, dest: at_gate, conditions: has_ticket}, {trigger: pass_gate, source: at_gate, dest: in_lobby, after: take_ticket_back}, # 场景3入座 {trigger: find_seat, source: in_lobby, dest: in_seat, after: sit_down}, # 场景4观看 {trigger: start_movie, source: in_seat, dest: watching, after: set_watched_true}, # 场景5离开 {trigger: end_movie, source: watching, dest: leaving, after: leave_cinema}, ] movie_goer MovieGoer() machine Machine(modelmovie_goer, statesstates, transitionstransitions, initialat_home) # 执行流程 print(f初始状态: {movie_goer.state}) movie_goer.go_to_box_office() print(f购票前: {movie_goer.state}, 票: {movie_goer.ticket}) movie_goer.buy_ticket() print(f购票后: {movie_goer.state}, 票: {movie_goer.ticket}) movie_goer.pass_gate() print(f检票后: {movie_goer.state}) movie_goer.find_seat() print(f入座后: {movie_goer.state}) movie_goer.start_movie() print(f观看中: {movie_goer.state}, 已观看: {movie_goer.watched}) movie_goer.end_movie() print(f离开后: {movie_goer.state})逻辑说明此代码将答案中线性的“场景1→场景2→...”转化为本文还有配套的精品资源点击获取
返回列表