题目描述
输入-版本一:
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]))