Description
对于计算机而言,颜色不过是像素点对应的一个 24 位的数值。现给定一幅分辨率为 M×N 的画,要求你找出万绿丛中的一点红,即有独一无二颜色的那个像素点,并且该点的颜色与其周围所有相邻像素的颜色差充分大。
Input
输入第一行给出三个正整数,分别是 M 和 N(≤ 1000),即图像的分辨率;以及 TOL,是所求像素点与相邻点的颜色差阈值,色差超过 TOL 的点才被考虑。随后 N 行,每行给出 M 个像素的颜色值,范围在 [0,2 24 ) 内。所有同行数字间用空格或 TAB 分开。
Output
在一行中按照 (x, y): color 的格式输出所求像素点的位置以及颜色值,其中位置 x 和 y 分别是该像素在图像矩阵中的列、行编号(从 1 开始编号)。如果这样的点不唯一,则输出 Not Unique;如果这样的点不存在,则输出 Not Exist。
参考程序
#满分程序
M,N,TOL=map(int,input().split())
graph=[]
ans=[]
color_dict={}
def Judge(i,j,M,N):
if i>=0 and i<=N-1 and j>=0 and j<=M-1:
return True
else:
return False
for i in range(N):
tmp=list(map(int,input().split()))
for j in tmp:
try:
color_dict[j]+=1
except:
color_dict[j]=1
graph.append(tmp)
for i in range(N):
for j in range(M):
if color_dict[graph[i][j]]!=1:
continue
#下面测试(i,j)的8个邻居
if Judge(i-1,j-1,M,N):#邻居点是合法的
if abs(graph[i][j]-graph[i-1][j-1])<=TOL:#色差不满足条件
continue
else:
pass#不合法则不考虑该邻居,换一个邻居
if Judge(i-1,j,M,N):
if abs(graph[i][j]-graph[i-1][j])<=TOL:
continue
else:
pass
if Judge(i-1,j+1,M,N):
if abs(graph[i][j]-graph[i-1][j+1])<=TOL:
continue
else:
pass
if Judge(i,j-1,M,N):
if abs(graph[i][j]-graph[i][j-1])<=TOL:
continue
else:
pass
if Judge(i,j+1,M,N):
if abs(graph[i][j]-graph[i][j+1])<=TOL:
continue
else:
pass
if Judge(i+1,j-1,M,N):
if abs(graph[i][j]-graph[i+1][j-1])<=TOL:
continue
else:
pass
if Judge(i+1,j,M,N):
if abs(graph[i][j]-graph[i+1][j])<=TOL:
continue
else:
pass
if Judge(i+1,j+1,M,N):
if abs(graph[i][j]-graph[i+1][j+1])<=TOL:
continue
else:
pass
ans.append([j+1,i+1,graph[i][j]])
if len(ans)==0:
print("Not Exist")
elif len(ans)==1:
print("({0}, {1}): {2}".format(ans[0][0],ans[0][1],ans[0][2]))
else:
print("Not Unique")
分析:
本题为PAT (Basic Level)1068题。从本题的编程技术或算法设计角度来说,并不难,只是通过全部测试样例,需要格外注意审题,理解题目和给出的测试样例。我结合优快云上其他大佬的解题经验以及个人体会,总结出以下几点需要注意的地方:
①纠正原题的描述:“该点的颜色与其周围 8 个相邻像素的颜色差充分大”,应改为“该点的颜色与其周围所有相邻像素的颜色差充分大”,应考虑最外围的数据。也有可能是目标点;
②充分理解“独一无二”:这个含义是指,可能存在某个点,它的所有邻居点的像素都满足这个“色差”要求,但是这个点的像素(颜色)在整个矩阵中出现不止一次,那么它就不是独一无二的,因此这样的点不是目标点;
③如何判断是否独一无二:创建字典,在输入数据的同时对每个颜色值统计次数,字典的键:值关系是,颜色值:出现的次数,这样检索较快,也不占用太大空间。
在这里还有一个技巧,就是更新字典时,善用异常处理机制也能给提高效率!判断颜色是否存在于字典中的键时,可以不用in关键字判断,直接交给键查找异常KeyError来处理!(无异常说明键存在,则更新值,有异常则创建键)
如果将输入的颜色平铺成一位数组(N×M个数据),使用count方法会超时!原因是,对于每个点的遍历是O(N×M),然而在这个N×M个数据的一位数组上利用count方法计数,则内层相当于又嵌套了O(N×M),所以时间性能十分低下。
如果采用“以空间换时间”的策略,开2^24的列表存储颜色值的出现次数,虽然时间复杂度降低了,但是这样会内存超限。
综上所述,字典在两者之间作出了平衡。
④充分理解“色差”:差值要加上绝对值再和TOL作比较。
这道题我肝了好久,从代码逻辑到性能优化,提交了不下二三十遍,在这个过程中非常感谢优快云上其他大佬的经验分享。这段时间刷了好多PAT乙级题,我不由得感叹PAT题还真的不能小觑,都很精品!一道编程题其实也考查了好多知识点,需要选择合适的程序结构、数据结构,同时也要在时间复杂度和空间复杂度之间做出很好的权衡。欢迎各位大佬批评指正,不吝赐教~