Squarefinder - ค้นหา tetragons ปกติ


27

ลองนึกภาพสี่เหลี่ยมจัตุรัสที่วาดบนระนาบสี่เหลี่ยมแต่ละอันมีจุดยอดที่พิกัดจำนวนเต็มและด้านข้างขนานกับแกน

ป้อนคำอธิบายรูปภาพที่นี่

รูปสี่เหลี่ยมผืนผ้าแบ่งส่วนของเครื่องบินออกเป็นส่วน ๆ ของส่วนที่แยกออกซึ่งมีสีแดงและน้ำเงินด้านล่าง:

ป้อนคำอธิบายรูปภาพที่นี่

เป้าหมายของคุณคือการหาจำนวนของพื้นที่ดังกล่าวซึ่งเป็นสี่เหลี่ยมที่สมบูรณ์แบบ ในตัวอย่างด้านบนมีสาม:

ป้อนคำอธิบายรูปภาพที่นี่

โปรดทราบว่าสี่เหลี่ยมขนาดใหญ่ที่อยู่ตรงกลางจะไม่ถูกนับเนื่องจากไม่ใช่พื้นที่เดียว แต่ถูกสร้างขึ้นจากพื้นที่ที่มีขนาดเล็กกว่าหลายจุด

อินพุต

คุณสามารถเขียนฟังก์ชั่นหรือโปรแกรมเต็มรูปแบบสำหรับความท้าทายนี้

อินพุตจะเป็น4nจำนวนเต็มที่ไม่ใช่ค่าลบซึ่งกำหนดnสี่เหลี่ยมในระนาบ แต่ละรูปสี่เหลี่ยมผืนผ้าเป็นตัวแทนจากสองจุดตรงข้ามเช่น4 9 7 8แสดงให้เห็นถึงรูปสี่เหลี่ยมผืนผ้าที่มีจุดตรงข้ามและ(4, 9) (7, 8)โปรดทราบว่าสี่เหลี่ยมผืนผ้านี้อาจจะมีการแสดงเป็นหรือ7 8 4 94 8 7 9

รูปแบบการป้อนข้อมูลที่แน่นอนมีความยืดหยุ่น (เช่นสตริงคั่นด้วยช่องว่าง, สตริงคั่นด้วยเครื่องหมายจุลภาค, อาร์เรย์จำนวนเต็มเดียว, รายการพิกัด tuples และอื่น ๆ ) แต่โปรดสมเหตุสมผลและยกตัวอย่างวิธีการเรียกใช้โค้ดของคุณในโพสต์ของคุณ คุณไม่สามารถจัดลำดับอินพุตใหม่ได้

เพื่อความง่ายคุณสามารถสรุปได้ว่าจะไม่มีการซ้อนสองขอบซึ่งรวมถึงการซ้อนทับที่จุดสุดยอด โดยเฉพาะอย่างยิ่งนี่ก็หมายความว่าไม่มีรูปสี่เหลี่ยมผืนผ้าสองรูปใดที่จะสัมผัสจากมุมหนึ่งไปยังอีกมุมหนึ่งและจากมุมหนึ่งไปยังอีกมุมหนึ่ง

เอาท์พุต

โปรแกรมของคุณควรพิมพ์หรือคืนค่าจำนวนเต็มเดียวซึ่งเป็นจำนวนของพื้นที่สี่เหลี่ยมจัตุรัส

เกณฑ์การให้คะแนน

นี่คือโค้ดกอล์ฟดังนั้นโค้ดในจำนวนไบต์ที่น้อยที่สุดจะเป็นผู้ชนะ


กรณีทดสอบ

การป้อนข้อมูล:

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

สี่เหลี่ยมขนาดใหญ่สองอันซ้อนทับกัน

คำตอบ:


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

คำอธิบาย

แบบสอบถามจะสร้างรูปทรงเรขาคณิตสำหรับแต่ละคู่พิกัด สหภาพวงแหวนด้านนอกเพื่อโหนบรรทัดอย่างถูกต้อง เปลี่ยนผลลัพธ์เป็นรูปหลายเหลี่ยมและทดสอบความกว้างต่อความสูงและพื้นที่สองเท่าเทียบกับผลรวมของแต่ละด้านกำลังสอง

มันจะทำงานเป็นแบบสอบถามแบบสแตนด์อโลนในฐานข้อมูล PostgreSQL ใด ๆ ที่มีส่วนขยาย PostGIS

แก้ไขพบสองสามเพิ่มเติม



@optimizer ฉันสงสัยมันจะมีอายุ :)
MickyT

@MickyT นี่กลายเป็นการแข่งขันที่ดี :)
Zgarb

@zgarb มันมีบิต :-) แต่ฉันไม่คิดว่าฉันจะมีอะไรอีกแล้ว
มิกกี้

13

Python 2 480 436 386 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
ฉันประทับใจมากที่คุณแก้ไขปัญหานี้ได้อย่างรวดเร็วและวิธีที่คุณเข้าถึงปัญหา! ห่วงสำหรับทำให้ฉันไป "แน่นอนว่าบางสิ่งสามารถทำได้ ... "
Sp3000

@ Sp3000 ใช่ ฉันลองใช้itertoolsกับลูป แต่มันก็นานขึ้น ฉันสามารถโกนได้สองถึงสามไบต์ด้วยการexecแทนที่สตริง + แต่ไม่มีอะไรน่าตื่นเต้นเกินไป
Ell

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 )โดยที่nคือขอบเขตทั้งหมดของ rectangles ทั้งหมดในอินพุต) ที่ฉันไม่สามารถประเมินได้ในสองกรณีทดสอบล่าสุด เมื่อฉันรวบรวมมันด้วยการปรับให้เหมาะสมเปิดใช้งานและรันในการ[(0,249,250,0),(2,1,357,714)]ทดสอบครั้งสุดท้ายของการทดสอบครั้งสุดท้าย400 ครั้งมันจะเสร็จในเวลาไม่เกิน 12 วินาที จากกรณีนี้กรณีทดสอบจริงจะเสร็จสิ้นในเวลาประมาณ 25 ปี

คำอธิบาย (บางส่วนฉันจะขยายสิ่งนี้เมื่อฉันมีเวลา)

ก่อนอื่นเราสร้างสองรายการhและvดังนี้ สำหรับแต่ละสี่เหลี่ยมผืนผ้าในอินพุตเราแบ่งเส้นขอบออกเป็นเซ็กเมนต์ของความยาว 1 จุดสิ้นสุดทิศตะวันตกของส่วนแนวนอนจะถูกเก็บไว้hและจุดสิ้นสุดทิศใต้ของส่วนแนวตั้งvเป็นรายการ[x,y]ความยาว 2 พิกัดในvถูกเก็บไว้ในสิ่งที่ตรงกันข้าม แบบฟอร์ม[y,x]สำหรับเหตุผลการเล่นกอล์ฟ จากนั้นเราก็วนรอบรายการทั้งสองและค้นหาขอบแนวนอน[x,j]และขอบแนวตั้ง[i,y]เช่นนั้นx < iและi-x == j-y(ดังนั้นพวกเขาจึงเป็นมุมตะวันตกเฉียงเหนือและตะวันออกเฉียงใต้ของสี่เหลี่ยม) และตรวจสอบว่าเส้นขอบของสี่เหลี่ยมอยู่ในรายการที่ถูกต้องhและvในขณะที่การตกแต่งภายใน พิกัดไม่ได้ จำนวนอินสแตนซ์ที่เป็นบวกของการค้นหาคือเอาต์พุต


ทำได้ดีฉันคิดว่าฉันจะต้องยอมรับตอนนี้ :)
MickyT

@MickyT เป็นเวลาหนึ่งสัปดาห์ดังนั้นฉันจึงยอมรับคำตอบของ Zgarb ในตอนนี้ แต่ถ้าคุณจัดการเพื่อเอาชนะได้ในภายหลังเครื่องหมายถูกอาจขยับ! สุจริตฉันประทับใจมากที่คุณทั้งสองสามารถไปได้ไกลแค่ไหน
Sp3000

@Zgarb เป็นผู้ชนะที่สมควรได้รับ :-)
MickyT

@ Sp3000 ขอบคุณสำหรับความท้าทายเล็กน้อยที่ดี
MickyT

@ Sp3000 ขอบคุณ! ฉันสนุกกับการเล่นกอล์ฟมาก
Zgarb
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.