如何在矩阵中查找唯一直线的数量

时间:2015-08-02 13:48:32

标签: algorithm math matrix line

我们已经给出了大小为M * N的矩阵,并且矩阵的每个位置内的值被表示为点。我们必须找到可以通过2个或更多点绘制的独特直线的数量。 例如。 M = 2,N = 2

*   *

*   *

可绘制的唯一线数为6。

类似地,如M = 2,N = 3

*    *    *

*    *    *

可绘制的唯一线数为11.

我无法找到解决此问题的方法。请帮助。

6 个答案:

答案 0 :(得分:4)

我认为,由于谷歌无处可寻,所以值得回答。这当然是一个有趣的问题,但下次尝试自己提供一些代码。

这是我的解决方案(原谅我的python有点生锈)

def notDiagonal(path):
    point1, point2 = path
    a1, a2 = point1
    b1, b2 = point2
    if(a1 == b1):
        return True
    if(a2 == b2):
        return True
    else:
        return False

N, M = 4, 2
matPoints, matPairs, bounds, edges = [], [], [], [(0,0),(N-1,0),(0,M-1),(N-1,M-1)]

def oneEdge(path):
    point1, point2 = path
    if (point1 not in edges and point2 not in edges) or (point1 in edges and point2 in edges):
        return False
    return True

for i in range(N):
    if (i,0) not in bounds:
        bounds.append((i,0))
    if (i,M-1) not in bounds:
        bounds.append((i,M-1))
    for j in range(M):
        matPoints.append((i, j))

for j in range(M):
    if (0,j) not in bounds:
        bounds.append((0,j))
    if (N-1,j) not in bounds:
        bounds.append((N-1,j))        

print("number of points is: ", len(matPoints))

for i in range(len(matPoints)-1):
    for j in range(i+1, len(matPoints)):
        matPairs.append(  ( matPoints[i], matPoints[j]  )   )
matPairCopy = list(matPairs)

print("number of lines before removal: ", len(matPairs))

for i in range(len(matPairs)):

    a = (matPairs[i][0][0] + matPairs[i][1][0])/2.0
    b = (matPairs[i][0][1] + matPairs[i][1][1])/2.0

    if(int(a) == a and int(b) == b):

            # Center point is (int(a), int(b))
            # Delete the partitioned lines if they exist (they may have been deleted before)

            if(  ((matPairs[i][0][0], matPairs[i][0][1]),   (int(a), int(b))) in matPairCopy):
                matPairCopy.remove(   ((matPairs[i][0][0], matPairs[i][0][1]),   (int(a), int(b)))    )
            if(  ((int(a), int(b))  ,  (matPairs[i][1][0], matPairs[i][1][1])   ) in matPairCopy     ):
                matPairCopy.remove(   ((int(a), int(b))  ,  (matPairs[i][1][0], matPairs[i][1][1])   ))

for k in matPairs:
    if(k[0] not in bounds or k[1] not in bounds):
        if(k in matPairCopy):
            matPairCopy.remove(k)
    elif(notDiagonal(k) and (oneEdge(k)) and k in matPairCopy):
                matPairCopy.remove(k)

print("number of lines after removing partitions: ",  len(matPairCopy))

已编辑:修正了小问题

N = 2,M = 2:输出= 6

N = 2,M = 3:输出= 11

N = 2,M = 4:输出= 18

N = 3,M = 3:输出= 20

N = 3,M = 4:输出= 31

答案 1 :(得分:2)

编辑时:我添加了一些代码来处理退化情况,其中M< 2和/或N< 2.出于测试目的,我能够从在线整数序列百科全书中重现this序列的前10个条目。

这是我的看法:计算水平和垂直的数量是微不足道的,所以集中在其他斜坡上。 (严格)正线和(严格)负斜率线之间存在1-1对应关系,因此计算正数并乘以2.要计算具有正斜率的线,我列举所有可能性a / b与a, b相对素数(因此斜率为缩小形式)。对于该斜率的每一行,我将其控制框称为高度a和宽度b的矩形,其特性是它不能长到尺寸为2 * ax 2 * b的矩形,并且具有相同的下限留在网格中的左角。在下面的非常优化的图中,该线是斜率1之一。它通过3个点。控制盒将是在顶行对角线切割的方形,而不是它在底行上切割的方形:

*   *   *   *
      /
*   *   *   *
  /     
*   *   *   *

我计算给定a,b的控制盒数量,计算放置axb的方法总数(第一个尺寸是高度)框减去放置这样一个框的方法数量远远超过网格的右上角,他们有成长的空间。经过一些代数(以及大量的调试)后,我想出了以下Python 3代码:

from fractions import gcd

def distinctLines(m,n):
    if m == 0 or n == 0:
        return 0
    elif m == 1 and n == 1:
        return 0
    elif m == 1 or n ==1:
        return 1
    else:
        numLines = m + n
        slopes = ((a,b) for a in range(1,m) for b in range(1,n) if gcd(a,b) == 1)
        for a,b in slopes:
            numLines += 2*((m-a)*(n-b) - max(m-2*a,0)*max(n-2*b,0))
        return numLines    

示例输出:

>>> for n in range(10): print(distinctLines(3,n), end = ' ')

0 1 11 20 35 52 75 100 131 164 

答案 2 :(得分:0)

这是一个解决方案,但在性能测量中不一定是一个好的解决方案:

列出所有点对(M*N choose 2)的列表,并为每对(a, b)检查是否有任何其他点c在同一行。如果是,请从列表中删除(a, c)(b, c)

你留下了由成对点代表的所有唯一线条。

答案 3 :(得分:0)

将问题分成几个部分:

  • 找到一条线的音高可以容纳的所有不同值:这些音高必须位于统一圆上(0 , -1)(包含)和(0 , 1)(仅限)之间。除了(0 , -1)(1 , 0)之外,每个音调(x , y)都有一个定义为(x , -y)的对等项符合要求。所以基本上这组有效音高将是 {(0,-1),(1,0)} merge D:{da , db|da=(1,y), y=m/n with 0 <= M < M and 0 < n < N , db=(1 , y(db)}。寻找不同的投球有点困难(我建议简单地强行使用这部分)。
  • 找到该行的每个不同音高的行数:具有音高(0 , -1)的行可以精确插入M次,音高(1 , 0)的行恰好N }次,对于以下任何其他行适用:让音调为(x , y),其中xy为整数。这个音高有N - x + M - y行,至少有2点。球场名单的要求:
    • 列表中的每个项目都是唯一的:对于p = (x , y)投球b = (u , v)x = d * uy = d * v。{/ li>
    • 列表中的每个项目都包含整数:对于任何音高p = (x , y)xy必须为整数

对于可怕的解释方式感到抱歉,无法找到任何工具来生成更多的数学符号。

答案 4 :(得分:0)

如果你想要一个强力解决方案here是一个python实现。基本上,它遍历所有点对,并且只保留正常形式的唯一线。以下是示例输出

M =  1    N =  1    Count =  0
M =  1    N =  2    Count =  1
M =  1    N =  3    Count =  1
M =  1    N =  4    Count =  1
M =  1    N =  5    Count =  1
M =  1    N =  6    Count =  1
M =  1    N =  7    Count =  1
M =  1    N =  8    Count =  1
M =  1    N =  9    Count =  1
M =  2    N =  2    Count =  6
M =  2    N =  3    Count =  11
M =  2    N =  4    Count =  18
M =  2    N =  5    Count =  27
M =  2    N =  6    Count =  38
M =  2    N =  7    Count =  51
M =  2    N =  8    Count =  66
M =  2    N =  9    Count =  83
M =  3    N =  3    Count =  20
M =  3    N =  4    Count =  35
M =  3    N =  5    Count =  52
M =  3    N =  6    Count =  75
M =  3    N =  7    Count =  100
M =  3    N =  8    Count =  131
M =  3    N =  9    Count =  164
M =  4    N =  4    Count =  63
M =  4    N =  5    Count =  96
M =  4    N =  6    Count =  141
M =  4    N =  7    Count =  188
M =  4    N =  8    Count =  246
M =  4    N =  9    Count =  309
M =  5    N =  5    Count =  145
M =  5    N =  6    Count =  214
M =  5    N =  7    Count =  282
M =  5    N =  8    Count =  371
M =  5    N =  9    Count =  466
M =  6    N =  6    Count =  314
M =  6    N =  7    Count =  415
M =  6    N =  8    Count =  546
M =  6    N =  9    Count =  687
M =  7    N =  7    Count =  548
M =  7    N =  8    Count =  723
M =  7    N =  9    Count =  910
M =  8    N =  8    Count =  954
M =  8    N =  9    Count =  1201
M =  9    N =  9    Count =  1512

替代方法

如何使用检测线条的Hough Transform变体。通常,Hough变换使用累加器将线组合成半径和角度的区间。但是,对于固定的M和N,您可以确定半径和角度方向上的最小分辨率,以便获得准确的答案。

例如,使用左上角点作为原点计算所有点的所有线半径和角度的集合。对于所有其他点,这些值应该相同。但是,您还必须在其他三个象限中包含对应的角度。

然后,使用累加器箱中心的值运行Hough变换。 bin大小必须是上面计算的值中的最小分辨率。计数大于1的任何累加器仓表示通过它的多个点的线。添加它们就是你的答案。

答案 5 :(得分:0)

除了上面的其他答案:

这是On lines and their intersection points in a rectangular grid of points文章Seppo Mustonen的主题。我通过在整数序列的在线百科全书中查找John Coleman的输出0 1 11 20 35 52 75 100 131 164找到了这一点,它指出了序列A160843