在平面直角坐标系中,两点可以确定一条直线。如果有多点在一条直线上,那么这些中任意两点确定的直线是同一条。
给定平面上2X3个整点{(x,y)|0≤x<2,0≤y<3,x∈Z,y∈Z},横坐标是0到1(包含0和1)之间的整数、纵坐标是0到2(包含0和2)之间的整数的点。这些点一共确定了11条不同的直线。
给定平面上20x21个整点{(x,y)|0≤x<20,0≤y<21,x∈Z,y∈Z},横坐标是0到19(包含0和19)之间的整数、纵坐标是0到20(包含0和20)之间的整数的点。
请问这些点一共确定了多少条不同的直线。
总体思路 值得我们注意的一个点是我们需要确定的是不同的直线,而非不同的线段。因此会有相同的直线经过不同的多个点。这时我们考虑到为了表示这样的含义,我们利用斜率和截距的方式可以很好的进行表示:
y = k x + b ; k = ( y 2 − y 1 ) / ( x 2 − x 1 ) y = kx + b; k = (y2-y1)/(x2-x1) y=kx+b;k=(y2−y1)/(x2−x1)
我们通过确定不同的点之间确定的斜率与截距,将其放入集合中,利用集合的特征(唯一性)对重复的直线进行筛选。我们先将垂直于x轴的直线(斜率不存在的直线)排除在外,再统计其余的直线。
ptslist = [(x,y) for x in range(20) for y in range(21)]# 确定点列表。平面上20x21个整点{(x,y)|0≤x<20,0≤y<21,x∈Z,y∈Z}kdset = set()# 构建一个集合用于存储斜率和截距# print(type(kdset))for cor1 in ptslist: for cor2 in ptslist: # print(cor1,cor2) if cor1[0] != cor2[0]:# 将斜率不存在的直线排除在外 k = (cor2[1]-cor1[1])/(cor2[0]-cor1[0]) d = cor2[1]-k*cor2[0] kdset.add((round(k,10),round(d,10))) #这里有一个小问题,如果我们不将其保留一定的小数位的话,我们所得到的结果与答案不符。print(len(kdset)+20)
其中如果我们不将其保留一定的小数位的话,我们所得到的结果(47753)与答案(40257)不符。这个问题也希望各位能够帮忙解答一下,我个人理解可能是在系统内四舍五入时出现了差异。
思路二我个人理解的话,虽然python是面向对象的语言,比赛中如果能够灵活地应用好,能够提高解题的理解和效率。但同时,如果能够使用简单的代码就可以解决问题,完全可以不用构建类。
class Line(object):"""构建线对象""" def __init__(self): self.k = 0 self.b = 0 # 定义魔法方法,对其进行排序 def __lt__(self, t): if self.k != t.k: return self.k < t.k return self.b < t.bN = 300000n = 0# 构造列表l,其中每一个元素都是类里的一个特殊对象l = [Line() for _ in range(N)]for x1 in range(0, 20): for y1 in range(0, 21): for x2 in range(0, 20): for y2 in range(0, 21): if x1 != x2: k = float((y2 - y1)) / (x2 - x1) b = float(y2 - k * x2) l[n].k = k l[n].b = b n += 1L = l[0: n]# 进行切片处理,取出含有斜率和截距的列表L.sort()# 进行排序res = 1for i in range(1, n):# 对斜率和截距不同的进行计数 if abs(L[i].k - L[i - 1].k) > 1e-8 or abs(L[i].b - L[i - 1].b) > 1e-8: res += 1print(res + 20)