字节跳动2018.10.8笔试 地震逃生选择

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/anlian523/article/details/82981293

题目描述

在这里插入图片描述
输入-版本一:
3
0,-1,1,0
0,0,0,-1
0,-1,0,-1
1,-1,0,0
输入-版本二:
3
0,-1,0,0
0,1,1,-1
0,-1,0,-1
0,-1,0,0

深度遍历

原来的1和-1都会变成0,原来的0有两种情况,如果这个0与某个1即出口的距离<=k,那么这个0还是0,否则为1。
建立一个同样的大小的二维数组second(每个元素初值为0),然后对每个1进行最大深度为k的深度遍历,遇到1或者-1就忽略,遇到0就把second里面的对应位置second[row][column]赋值为1。
需要注意每次深度遍历都是独立的,不能说是A开始遍历走过的点,然后B开始遍历就不能A走过的这些点。
所有深度遍历结束后,second[row][column]为1说明这个元素与某个1之间的距离<=k,second[row][column]为0说明这个元素与每个1之间的距离都>k。

k  = eval(input())
li = []#原数组
exitLi = []#记录出口

def readexit(index,exitlist):
    #读取出口
    global exitLi
    if 1 in exitlist:
        for i in range(len(exitlist)):#一排里面可能有几个1
            if exitlist[i] == 1:
                exitLi.append([index, i])

#先读取第一行
temp = list(map(int,input().split(',')))
readexit(0,temp)
li.append(temp)
n = len(temp)
#新建一个矩阵
second = [[0 for i in range(n)] for j in range(n)]
for i in range(1, len(temp)):
    temp = list(map(int,input().split(',')))
    readexit(i,temp)
    li.append(temp)
#深度遍历每个起点
def recur(row,column,step):
    if step >= k:
        #大于三就返回
        return 
    if 0 <= column+1 <=n-1:
        if (li[row][column+1] != -1) and (li[row][column+1] != 1):
            #忽略墙和起点
            second[row][column+1] = 1
            recur(row,column+1,step+1)
    if 0 <= column-1 <=n-1:
        if (li[row][column-1] != -1) and (li[row][column-1] != 1):
            #忽略墙和起点
            second[row][column-1] = 1
            recur(row,column-1,step+1)
    if 0 <= row+1 <=n-1:
        if (li[row+1][column] != -1) and (li[row+1][column] != 1):
            #忽略墙和起点
            second[row+1][column] = 1
            recur(row+1,column,step+1)            
    if 0 <= row-1 <=n-1:
        if (li[row-1][column] != -1) and (li[row-1][column] != 1):
            #忽略墙和起点
            second[row-1][column] = 1
            recur(row-1,column,step+1)
for i in exitLi:
    row = i[0]
    column = i[1]
    recur(row,column,0)

#按照second里面的1进行赋值
for i in range(n):
    for j in range(n):
        if (li[i][j] == 1) or (li[i][j] == -1):
            li[i][j] = '0'
        elif li[i][j] == 0:
            #两种情况
            if second[i][j] == 1:
                li[i][j] = '0'
            else:
                li[i][j] = '1'

for i in range(n):
    print(','.join(li[i]))

通过率为75%。提示超时。这个因为当1与1之间相隔比较近,就会有许多点被重复的递归到,下一章讲一下优化方法,但没有平台让我验证优化后的代码通过率能否达到100%。
最大的问题是,在每次的深度递归中,不仅会重复遍历点,还会往回遍历点。
输入为如下,在递归函数里增加语句print(row,column),会发现本章代码有大量重复遍历:
3
0,0,0,0,0
0,0,0,0,0
0,0,1,0,0
0,0,0,0,0
0,0,0,0,0
虽然大量重复遍历,但输出正确:
在这里插入图片描述
second数组元素其实就是代表该元素有没有被遍历过即相当于visited,但这里的代码也不能设置为visited为1即访问过就停止深度遍历,使用如上输入,递归函数修改为如下,即visited为1就不再递归。

def recur(row,column,step):
    print(row,column)
    if step >= k:
        #大于三就返回
        return 
    if 0 <= column+1 <=n-1:
        if (li[row][column+1] != -1) and (li[row][column+1] != 1):
            if second[row][column+1] == 0:
                #忽略墙和起点
                second[row][column+1] = 1
                recur(row,column+1,step+1)
    if 0 <= column-1 <=n-1:
        if (li[row][column-1] != -1) and (li[row][column-1] != 1):
            if second[row][column-1] == 0:
                #忽略墙和起点
                second[row][column-1] = 1
                recur(row,column-1,step+1)
    if 0 <= row+1 <=n-1:
        if (li[row+1][column] != -1) and (li[row+1][column] != 1):
            if second[row+1][column] == 0:
                #忽略墙和起点
                second[row+1][column] = 1
                recur(row+1,column,step+1)            
    if 0 <= row-1 <=n-1:
        if (li[row-1][column] != -1) and (li[row-1][column] != 1):
            if second[row-1][column] == 0:            
                #忽略墙和起点
                second[row-1][column] = 1
                recur(row-1,column,step+1)

运行结果如下,为错误输出:
在这里插入图片描述
错误输出的原因如下:
在这里插入图片描述
在某一时刻,递归往右走完,红色为已经遍历过的点,由于设置了visited,这些点不能再被遍历到了。
在这里插入图片描述
之后递归再向左遍历,蓝色代表能达到的范围,但绿色矩阵本来也应该可以到达,但由于有个红色挡住了,所以绿色区域就不能被遍历到了,所以就造成了错误输出。

优化递归次数

还是建立一个同样的大小的二维数组second,但另每个元素初值为-1,定义second每个元素的含义为传播能力,比如起点的传播能力为k,那么起点对应到second的那个元素的值就设为k;从起点递归到了下一个点A,那么A对应到second的那个元素的值就设为k-1,,以此类推,递归终点的点就会被设置为0。
在递归函数recur中,k-step-1即k-(step+1)为当前递归的传播能力,second对应元素的值为已经记录的传播能力:
如果当前递归的传播能力>已经记录的传播能力,那么继续递归,更新传播能力。
如果当前递归的传播能力<=已经记录的传播能力,那么停止递归。
在这里插入图片描述
如上图所示,假设有一个点1即出口的深度遍历是这样,红色数字表示了每个点的传播能力。
在这里插入图片描述
现在有另一个出口,它的传播能力是蓝色字体,当它传播到了虚线矩形区域时,当前传播能力就不大于已记录能力了,此时就应该停止深度遍历。这样就减小了递归次数。

优化的地方在于:最起码递归不会往回走了,传播能力小的也不会继续递归了,但还是会有一定的重复的遍历。

k  = eval(input())
li = []#原数组
exitLi = []#记录出口

def readexit(index,exitlist):
    #读取出口
    global exitLi
    if 1 in exitlist:
        for i in range(len(exitlist)):#一排里面可能有几个1
            if exitlist[i] == 1:
                exitLi.append([index, i])

#先读取第一行
temp = list(map(int,input().split(',')))
readexit(0,temp)
li.append(temp)
n = len(temp)
#新建第二个矩阵
second = [[-1 for i in range(n)] for j in range(n)]
for i in range(1, len(temp)):
    temp = list(map(int,input().split(',')))
    readexit(i,temp)
    li.append(temp)
#深度遍历每个起点
def recur(row,column,step):
    if step >= k:
        #大于三就返回
        return 
    if 0 <= column+1 <=n-1:
        if (li[row][column+1] != -1) and (li[row][column+1] != 1):
            #忽略墙和起点
            if (k-step-1) > second[row][column+1]:
                #如果当前传播能力大于已有传播能力,才进行递归
                second[row][column+1] = k-step-1
                recur(row,column+1,step+1)
    if 0 <= column-1 <=n-1:
        if (li[row][column-1] != -1) and (li[row][column-1] != 1):
            #忽略墙和起点
            if (k-step-1) > second[row][column-1]:
                second[row][column-1] = k-step-1
                recur(row,column-1,step+1)
    if 0 <= row+1 <=n-1:
        if (li[row+1][column] != -1) and (li[row+1][column] != 1):
            #忽略墙和起点
            if (k-step-1) > second[row+1][column]:
                second[row+1][column] = k-step-1
                recur(row+1,column,step+1)            
    if 0 <= row-1 <=n-1:
        if (li[row-1][column] != -1) and (li[row-1][column] != 1):
            #忽略墙和起点
            if (k-step-1) > second[row-1][column]:
                second[row-1][column] = k-step-1
                recur(row-1,column,step+1)
for i in exitLi:
    row = i[0]
    column = i[1]
    second[row][column] = 3
    #手动设置起点的传播能力
    recur(row,column,0)

#按照second里面的1进行赋值
for i in range(n):
    for j in range(n):
        if (li[i][j] == 1) or (li[i][j] == -1):
            li[i][j] = '0'
        elif li[i][j] == 0:
            #两种情况
            if second[i][j] >= 0:
                li[i][j] = '0'
            else:
                li[i][j] = '1'

for i in range(n):
    print(','.join(li[i]))

猜你喜欢

转载自blog.csdn.net/anlian523/article/details/82981293
今日推荐