如何有效地计算nxm矩形网格中右等腰三角形的数量?
答案 0 :(得分:3)
设A是直角所在的三角形角。设ab是第一个角的差矢量,而是另一个角的差矢量。 ac应始终留在ab。因此,对于给定的ab,我们可以将ac计算为:
ac = (-ab.y, ab.x)
因此,给定A,某个三角形只有两个整数自由度。我们可以计算ab的可能间隔:
A.x + ab.x >= 0 --> ab.x >= -A.x
A.x + ab.x <= m --> ab.x <= m - A.x
A.y + ab.x >= 0 --> ab.x >= -A.y
A.y + ab.x <= n --> ab.x <= n - A.y
A.y + ab.y >= 0 --> ab.y >= -A.y
A.y + ab.y <= n --> ab.y <= n - A.y
A.x - ab.y >= 0 --> ab.y <= A.x
A.x - ab.y <= m --> ab.y >= A.x - m
所以可能的间隔是
xmin = max(-A.x, -A.y)
xmax = min(m - A.x, n - A.y)
ymin = max(-A.y, A.x - m)
ymax = min(n - A.y, A.x)
满足这些条件的可能向量的数量(0向量除外)是:
c = (xmax - xmin + 1) * (ymax - ymin + 1) - 1
所需结果是网格中所有可能A
的c之和。使用朴素的方法,您将获得O(grid cells)
运行时。根据你的网格,这已经足够快了。
为了分割c
的总和(在所有网格单元格上),我们必须确定max
和min
操作的结果在何处发生变化。例如。 ymax
更改如下:
请注意,我已经将线偏移了一点,因此从点到点所属的区域有一个独特的映射。
当我们对所有区间边界执行此操作时,我们得到以下图片(对于m> n):
现在我们可以独立计算每个区域c
的总和。我将示例性地显示最左边的三角形区域。
对于该地区,以下条件成立:
xmin = -A.y
xmax = n - A.y
ymin = -A.y
ymax = A.x
c(x, y) = (n - y + x) * (x + y) - 1
= (nx + ny - y^2 + x^2 - 1)
现在我们对该地区的所有x
和y
进行总结。 x
从0到n/2
。 y
从x
到n-x
。
所以我们得到:
n/2 n-x
sumLeftRegion = Sum Sum (nx + ny - y² + x² - 1)
x=0 y=x
我们可以解决这个问题(例如,使用您最喜欢的代数程序并获取:
sumLeftRegion = 1/48 * (2 + n)*(-24 - 14n + 6n^2 + 5n^3)
可以对所有其他地区进行此操作。您需要一些案例(例如m > n
,m = n
,m < n
,可能是偶数n
和m
)。通过旋转网格(不会更改可能的三角形的数量),可以将案例n > m
转换为m > n
。这将是一些工作,但最终你会得到O(1)
的结果,因为没有迭代。
答案 1 :(得分:0)
考虑RAIT ABC。如果我们在(0,0)处保持三角形的拐角(A),那么我们可以说对于y = 1(so(1,1),(2,1)等的每个正点(B)存在一个RAIT,其另一个角(C)位于(n,n),其中Cn = Bx-1。显然,对于y = 2也必须为真(从B(2,2)开始,y = 3 (从B(3,3)等开始 - 你只是加倍,三倍,等等。这有帮助吗?(我不是数学家 - 如果不明显的话)
答案 2 :(得分:0)
考虑方框中的任何三角形。它有一个独特的边界框(在某种意义上它只有一个,而不是它是唯一带有该边界框的三角形)。因此,如果您考虑每个可能的边界框边长(i,j)
,并使用此边界框计算RAIT三角形的数量(表示此CP(i,j)
),那么您的答案为sum(i=1 to n, sum(j=1 to m,CP(i,j)*(m-j+1))*(n-i+1))
。 (m-j+1)*(n-i+1)
正在计算n*m
框中可容纳的大小框的数量。所以现在很难找到CP(i,j)
。同样,CP(i,j)
是RAIT三角形的数量,在框的周长上有点,长度为i
和j
。我们可以在这里使用对称性。假设不失一般性,直角是ABC。想象一下,三角形与正轴对齐。
A
|\
| \
B__C
现在考虑顺时针旋转它直到它自身回线。通过该过程有两种可能性:BC位于象限1和2或象限3和4中。
2|1
---
3|4
我们在这里注意到,在第一种情况下,B位于边界框的底部或右侧,而在第二种情况下,B位于边界框的顶部或左侧。所以wlog我们假设B位于底部或右侧,不包括左下角。
+-----*
| *
| *
+******
一旦我们计算出有多少个RAIT三角形有这个属性,我们就可以加倍它! 如果B位于右上角,则只有一个三角形可以测试RAIT-ness,如果它位于右下角则相同。如果它沿着右侧墙壁,那么有一些三角形要检查(在顶部的每个点放置C,并计算第三个点以查看它是否形成给定的边界框)。同样,如果它沿着底壁,那么有j个三角形要检查。
这肯定比O(m * n)差,它可能在O(m ^ 2 * n ^ 2)附近,但希望这会有所帮助。
修改
我们在测试三角形中实际上可以做得更好一点。通过一点几何直觉,我们可以看到,如果B沿着底部,并且更靠近右下角,则C位于右上角。同样,如果它更接近左下角,则A位于右上角。所以我们可以考虑B的一半位置,对于每个位置我们只需要考虑一个可能的三角形。 (B在右边的论点是相似的。)