左孩子右兄弟&&路径之谜

文章讲述了如何通过‘左孩子右兄弟’表示法将多叉树转化为二叉树,以及如何利用深度优先搜索(DFS)解决寻找唯一行走路径的问题。在多叉树转二叉树中,最高高度由节点子节点数量及最深子树深度决定;在箭靶问题中,DFS用于搜索满足条件的唯一路径,从西北角到东南角,每次移动后向北和西各射一箭,路径确保唯一。
摘要由CSDN通过智能技术生成

题目

对于一棵多叉树,我们可以通过 “左孩子右兄弟” 表示法,将其转化成一棵二叉树。

如果我们认为每个结点的子结点是无序的,那么得到的二叉树可能不唯一。

换句话说,每个结点可以选任意子结点作为左孩子,并按任意顺序连接右兄弟。

给定一棵包含 N​​ 个结点的多叉树,结点从 1​​ 至 N​ 编号,其中 1 号结点是根,每个结点的父结点的编号比自己的编号小。

请你计算其通过 “左孩子右兄弟” 表示法转化成的二叉树,高度最高是多少。

注:只有根结点这一个结点的树高度为 0​。

思路

最开始还以为是数学规律,看题解发现是去深度遍历每个节点的深度。每一层的节点存储在一个数组里面,由于使用左孩子右兄弟的表示法,则最高的高 = 该节点的孩子节点个数 + 孩子节点中最高的深度 

代码

import os
import sys
sys.setrecursionlimit(100000) #设置最深递归深度
# 请在此输入您的代码
N = int(input())
nodes = [[] for i in range(N+1)]
for i in range(2, N + 1): # 存储2​ 至 N 号结点的父结点编号
  j = int(input())
  nodes[j].append(i)

def dfs(i):
  if nodes[i] is None: #该层节点为空 即没有深度 返回0
    return 0
  
  maxn = 0
  for j in nodes[i]:#遍历第i层子节点的深度
    maxn = max(maxn, dfs(j))

  deep = maxn
  return len(nodes[i]) + deep # 第i层的子节点(每一个子节点变成二叉树都是一层高度) + 子节点中最深的深度

print(dfs(1))

题目

小明冒充 X 星球的骑士,进入了一个奇怪的城堡。

城堡里边什么都没有,只有方形石头铺成的地面。

假设城堡地面是 n×n 个方格。如下图所示。

 

按习俗,骑士要从西北角走到东南角。可以横向或纵向移动,但不能斜着走,也不能跳跃。每走到一个新方格,就要向正北方和正西方各射一箭。(城堡的西墙和北墙内各有 n 个靶子)同一个方格只允许经过一次。但不必走完所有的方格。如果只给出靶子上箭的数目,你能推断出骑士的行走路线吗?有时是可以的,比如上图中的例子。

本题的要求就是已知箭靶数字,求骑士的行走路径(测试数据保证路径唯一)

思路

 使用dfs,多了一个判断西边和北边靶子上箭数目的条件。但是我还是不会写dfs,去查了题解,这个写得很清楚——>https://alex007.blog.csdn.net/article/details/90314923​​​​​​

有一个测试用例没有通过,超时了。 

代码 

import os
import sys

# 请在此输入您的代码
def dfs(r, c):
    """
    Args:
        r: 当前搜索行
        c: 当前搜索列
    Returns: Bool值,表示是否找到了一条符合条件路径
    """
    if r == n - 1 and c == n - 1: # 到达右下角
        if sum(north_target) > 0 or sum(west_target) > 0:  # 如果最后还有箭靶上面的数目不为零,也不符合要求
            return False
        path.append(r * n + c)
        print(' '.join(map(str, path)))
        return True

    path.append(r * n + c)
    direction = [(0, 1), (1, 0), (0, -1), (-1, 0)]
    for dr, dc in direction:
        nr, nc = r + dr, c + dc  # 下一个搜索位置的行、列

        # 保证下一个搜索的位置符合要求
        if -1 < nr < n and -1 < nc < n and not visit[nr][nc] and north_target[nc] > 0 and west_target[nr] > 0:
            visit[nr][nc] = True
            north_target[nc] -= 1
            west_target[nr] -= 1

            if dfs(nr, nc):
                return True
            else: #该路径走不通 则撤销刚才的操作 标记该点未被访问 靶数分别+1 路径将该点删除
                visit[nr][nc] = False
                north_target[nc] += 1
                west_target[nr] += 1

    path.pop()
    return False


if __name__ == '__main__':
    n = int(input())
    north_target = list(map(int, input().split()))
    west_target = list(map(int, input().split()))

    path = []
    visit = [[False] * n for _ in range(n)]  # 标记该点是否被访问过

    visit[0][0] = True
    north_target[0] -= 1
    west_target[0] -= 1
    dfs(0, 0)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值