题目
班里 N 个小朋友,每个人都有自己最崇拜的一个小朋友(也可以是自己)。
在一个游戏中,需要小朋友坐一个圈,每个小朋友都有自己最崇拜的小朋友在他的右手边。
求满足条件的圈最大多少人?
小朋友编号为 1,2,3,⋯N。
思路
将每个小朋友都作为一个起点,来依次向下进行遍历,同时对已经遍历过的小朋友进行标记,当下一个小朋友是已经遍历过的时候,就表示此时的path中已经有了一个圈了。将栈中的数据一个一个往外pop,来获得这个圈的长度。最后将长度最大的圈进行输出。
我这个还是太暴力了,有两个用例运行超时了。
代码
import os
import sys
# 请在此输入您的代码
sys.setrecursionlimit(1000000) #设置最大递归深度
N = int(input())
a = list(map(int, input().split()))
person = {} #每个小朋友右手边的人以字典进行储存
for i in range(1, N+1):
person[i] = a[i-1]
def find(x):
if vist[x] == 1: #该小朋友已被访问过 即形成了一个圈
now_x = path.pop()
rel_path = [] #存储圈中所包含的人
count = 1
while now_x != x:
rel_path.append(now_x)
count += 1
now_x = path.pop()
return count, rel_path
path.append(x)
vist[x] = 1
return find(person[x]) #这里也要有return 不然只有if中的return 返回的是这里调用递归算法的地方 而不是主函数 这样就会返回none
cle = [] #记录形成的圈里面的点
out = [] #记录以每个点为起点可以形成圈的长度
# vist = [0 for i in range(N+1)]
for i in range(1, N+1):
if i in cle : # 这些点就不用遍历了,因为这些点都在圈里面 不用再遍历一遍
continue
global vist #标记每个人是否已在当前圈里面
vist = [0 for i in range(N+1)]
global path # 记录以当前点位起点的圈
path = []
out_1, cle_1 = find(i)
out.append(out_1)
cle.append(x for x in cle_1)
print(max(out))
后面再写了一次
import os
import sys
sys.setrecursionlimit(1000000) #设置最大递归深度
# 请在此输入您的代码
def dfs(x):
global cir_len
if point[person[x]] == 1: # 当前小朋友崇拜的小朋友被访问过 形成一个圈 结束条件
temp = len(path) - path.index(person[x]) #计算圈的长度 整个路径的长度-闭合的另一个点在path中的位置 如5的崇拜对象为3 即在路径中3的位置 进行相减
cir_len.append(temp)
return True
if point[person[x]] == 0: #当前小朋友崇拜的小朋友 没有被访问过
point[person[x]] = 1
path.append(person[x])
dfs(person[x]) #这里没有去撤销 就是因为每个起点单独拥有一个point path矩阵
# point[person[x]] = 0 #如果全局只有一个point 则遍历完后需要撤销已访问操作
# point[x] = 0 #如果全局只有一个point 则遍历完后需要撤销已访问操作
return
N = int(input())
a = list(map(int, input().split()))
person = {} #每个小朋友右手边的人以字典进行储存
for i in range(1, N+1):
person[i] = a[i-1]
cir_len = [] #保存每个圈的长度
# point = [0 for i in range(N+1)] 全局只有一个point矩阵
for i in range(1, N+1):
point = [0 for i in range(N+1)]
path = [i] #记录每个圈中的结点
point[i] = 1 #初始化起点已被访问
dfs(i)
print(max(cir_len))
Tips:递归调用的时候,要注意return,调用的最外层也需要return函数,这样才是返回到主函数中。
题目
给定一个长度为 N 的数组A=[A1,A2,⋅⋅⋅,AN],数组中有可能有重复出现的整数。
现在小明要按以下方法将其修改为没有重复整数的数组。小明会依次修改A2,A3,⋅⋅⋅,AN。
当修改Ai 时,小明会检查Ai 是否在A1 ∼Ai−1 中出现过。如果出现过,则小明会给Ai 加上 1 ;如果新的Ai 仍在之前出现过,小明会持续给Ai 加 1 ,直 到 Ai 没有在 A1 ∼ Ai−1 中出现过。
当 AN 也经过上述修改之后,显然 A 数组中就没有重复的整数了。
现在给定初始的A 数组,请你计算出最终的A 数组。
思路
只会暴力,呜呜呜!查并集这个东西我都没听过,通过测试用例4个。
代码
import os
import sys
# 请在此输入您的代码
N = int(input())
datas = list(map(int, input().split()))
flag = [0 for i in range(10000000)] #标记该数字是否已存在
j = 0
for i in datas:
if flag[i] == 0: #该数第一次出现
flag[i] = 1 #标记后进入下一次循环
j += 1 #记录当前下标 用于修改当前值
continue
while flag[i] == 1: #该数第二次出现 则一直+到没有出现的数
i += 1
flag[i] = 1
datas[j] = i #修改当前值
j += 1
for i in datas:
print(i , end = ' ')
别人的代码(半懂不懂的 应该是引入数组fa表示本位置插入元素后,下一个等值元素应该插入的位置):
import os
import sys
# 请在此输入您的代码
N = int(input())
A = list(map(int, input().split()))
def find(x):
global fa
if fa[x] != x: # 只有当前fa[x] = x 表示才能将x放在当前位置 否则就要一层层去找可以放的位置
fa[x] = find(fa[x])
return fa[x]
# 首先创建数组大小的并查集序列 fa[i]表示,i=x产生冲突时应该将冲突的第二个x值放入的位置
fa = [i for i in range(1000001)]
for i in range(N):
A[i] = find(A[i])
fa[A[i]] = find(A[i] + 1) # 该元素放好好,要更新fa表 将该元素的fa更新为它后一个位置冲突后的插入位置
#print("i =" + str(A[i]) + ":" + str(fa)) 将当前fa打印出来 更好理解一点
for i in A:
print(i, end=' ')
絮絮叨:300复300,300何其多啊!感觉这次真打水漂了!