Squarefinder –定位规则四边形


27

想象一下在平面上绘制的一堆矩形,每个矩形的顶点在整数坐标处,并且其边平行于轴:

在此处输入图片说明

矩形将平面划分为多个不相交的区域,下面用红色和蓝色表示:

在此处输入图片说明

您的目标是找到这样的正方形的区域数量。在上面的示例中,有三个:

在此处输入图片说明

注意,中间的大方块不是一个单一的区域,因此不算在内,而是由几个较小的不相交的区域组成。

输入项

您可以为此挑战编写函数或完整程序。

输入将是在平面中4n定义n矩形的非负整数。每个矩形由两个相对的顶点4 9 7 8表示,例如代表具有相对的顶点(4, 9)和的矩形(7, 8)。请注意,此矩形也可以表示为7 8 4 94 8 7 9

确切的输入格式是灵活的(例如,以空格分隔的字符串,以逗号分隔的字符串,单个整数数组,坐标元组列表等),但是请保持合理,并举例说明如何在您的帖子中运行代码。您不能重新排序输入。

为简单起见,您可以假设没有两条边重叠-这包括在顶点处重叠。特别是,这意味着没有两个矩形将边到边或角到角接触,并且这些矩形将具有非零面积。

输出量

您的程序应打印或返回一个整数,即整数个正方形区域。

计分

这是代码高尔夫,所以最少字节的代码将获胜。


测试用例

输入:

0 0 5 5
6 8 10 4
14 16 11 13
19 1 18 2

输出:

4

这只是四个不相交的正方形:

在此处输入图片说明


输入:

2 1 3 11
1 10 5 19
6 10 11 3
8 8 15 15
13 13 9 5
15 1 19 7
17 19 19 17

输出:

3

这是帖子开头的示例测试用例。


输入:

0 9 15 12
6 3 18 15
9 6 12 20
13 4 17 8

输出:

7

在此处输入图片说明


输入:

5 9 11 10
5 12 11 13
6 8 7 14
9 8 10 14
13 8 14 9
13 10 14 14

输出:

14

在此处输入图片说明


输入:

0 99999 100000 0

输出:

0

这只是一个大矩形。


输入:

0 99999 100000 0
2 1 142857 285714

输出:

1

重叠的两个大矩形。

Answers:


9

SQL(POSTGIS),286 269 261 240 226 218 216

这是对PostGIS PostgreSQL扩展的查询。我还没有计算总数中的输入值。

SELECT SUM(1)FROM(SELECT(ST_Dump(ST_Polygonize(g))).geom d FROM(SELECT ST_Union(ST_Boundary(ST_MakeEnvelope(a,b,c,d)))g FROM(VALUES
-- Coordinate input
(2, 1, 3, 11)
,(1, 10, 5, 19)
,(6, 10, 11, 3)
,(8, 8, 15, 15)
,(13, 13, 9, 5)
,(15, 1, 19, 7)
,(17, 19, 19, 17)
)i(a,b,c,d))i)a WHERE(ST_XMax(d)-ST_XMin(d))^2+(ST_YMax(d)-ST_YMin(d))^2=ST_Area(d)*2

说明

该查询将为每个坐标对建立几何。结合外环以正确地将线连接起来。将结果转换为多边形,并针对高度测试宽度,针对每个边的平方和测试面积两倍。

使用PostGIS Extension,它将在任何PostgreSQL数据库上作为独立查询运行。

编辑发现了更多。


1
... and Haskell
Optimizer

@optimizer我怀疑它会持续
下去

@MickyT这已变成一场健康的比赛。:)
Zgarb 2014年

@zgarb有点:-)但我认为我没有其他事情要去了。
MickyT 2014年

13

Python 2 480436386 352字节

exec u"""s=sorted;H=[];V=[]
FRIinput():
 S=2*map(s,zip(*R))
 FiI0,1,2,3:
    c=S[i][i/2];a,b=S[~i]
    FeIs(H):
     C,(A,B)=e
     if a<C<b&A<c<B:e[:]=C,(A,c);H+=[C,(c,B)],;V+=[c,(a,C)],;a=C
    V+=[c,(a,b)],;H,V=V,H
print sum(a==A==(d,D)&c==C==(b,B)&B-b==D-d&1-any(d<X[0]<D&b<y<B Fy,XIH)Fb,aIH FB,AIH Fd,cIV FD,CIV)""".translate({70:u"for ",73:u" in ",38:u" and "})

通过STDIN以以下格式获取坐标对列表:

[  [(x, y), (x, y)],  [(x, y), (x, y)],  ...  ]

并将结果打印到STDOUT。


字符串替换后的实际程序是:

s=sorted;H=[];V=[]
for R in input():
 S=2*map(s,zip(*R))
 for i in 0,1,2,3:
    c=S[i][i/2];a,b=S[~i]
    for e in s(H):
     C,(A,B)=e
     if a<C<b and A<c<B:e[:]=C,(A,c);H+=[C,(c,B)],;V+=[c,(a,C)],;a=C
    V+=[c,(a,b)],;H,V=V,H
print sum(a==A==(d,D) and c==C==(b,B) and B-b==D-d and 1-any(d<X[0]<D and b<y<B for y,X in H)for b,a in H for B,A in H for d,c in V for D,C in V)

说明

该程序无需处理复杂的多边形,而是处理简单的线段。对于每个输入矩形,我们分别将其四个边中的每一个添加到集合段列表中。将一个段添加到列表中的步骤如下:我们测试每个现有段是否与新段相交;如果找到相交点,则在相交点将两个线段分开并继续。为了使事情变得容易,我们实际上保留了两个单独的细分列表:一个水平细分列表和一个垂直细分列表。由于线段不重叠,因此水平线段只能与垂直线段相交,反之亦然。更好的是,这意味着所有相交(不考虑同一矩形的边缘)都是“适当的”,即,我们没有T形相交,因此每个线段的“两侧”都被真正划分了。

一旦构建了段列表,便开始计算平方。对于四个线段(尤其是两个水平线段和两个垂直线段)的每种组合,我们测试它们是否形成正方形。此外,我们验证该顶点内没有顶点(例如,如果在较大的正方形内有一个较小的正方形,则可能发生)。这为我们提供了所需的数量。请注意,即使程序以不同的顺序对每个组合进行了四次测试,但线段坐标的特定顺序仍可保证我们仅对每个平方计数一次。


1
您解决问题的速度以及解决问题的方式给我留下了深刻的印象!for循环使我“肯定可以完成某些事情……”
Sp3000

@ Sp3000是的。我尝试使用itertools循环,但最终变得更长了。我可以用exec+字符串替换来剃掉一些字节,但是没有什么太令人兴奋的。
2014年

4

Haskell,276 266 250 237 225 222 217字节

它不断变得越来越短,而且变得更加模糊。

(x#i)l=mapM id[[min x i..max x i-1],l]
(y!j)l f=and[p l==p(f[y,j])|p<-map elem$f[y..j]]
s[h,v]=sum[1|[x,j]<-h,[y,i]<-v,x<i,i-x==j-y,(y!j)h$x#i,(x!i)v$y#j]
n=s.foldr(\(x,y,i,j)->zipWith(++)[x#i$[y,j],y#j$[x,i]])[[],[]]

评估n [(0,0,5,5),(6,8,10,4),(14,16,11,13),(19,1,18,2)]第一个测试用例。我认为我已经接近在Haskell上使用此算法的极限。

这个函数是如此之慢(至少为O(n 3,其中Ñ是在输入所有的矩形的总周长),我无法在最后两个测试用例评估它。当我在打开优化功能的情况下对其进行编译并[(0,249,250,0),(2,1,357,714)]在上次测试的400倍压缩版本上运行它时,它在12秒多的时间内完成了。基于此,实际的测试用例将在大约25年内完成。

说明(部分,我会在有空的时候进行扩展)

我们首先构建两个列表hv如下所示。对于输入中的每个矩形,我们将其边界分成长度为1的段。水平段的西端点存储在中h,而垂直段的南端点存储在中v,作为[x,y]长度2的列表。中的坐标v存储在反面由于[y,x]打高尔夫球的原因。然后,我们只是在这两个列表循环和搜索水平边缘[x,j]和垂直边缘[i,y],使得x < ii-x == j-y(所以他们是西北和正方形的东南角),并检查方的边界是在正确的名单hv,而内部坐标不是。搜索的肯定实例数是输出。


做得好,我想我现在不得不承认:)
MickyT 2014年

@MickyT已经一个星期了,所以我现在已经接受了Zgarb的回答,但是如果您以后能击败它,则复选标记可能会移动!老实说,你们两个人走了多远给我留下了深刻的印象
-Sp3000

@Zgarb当之无愧的胜利:-)
MickyT

@ Sp3000感谢您的挑战。
MickyT 2014年

@ Sp3000谢谢!打高尔夫球让我很开心。
Zgarb 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.