วางหมุดสี่เหลี่ยมลงในรูสี่เหลี่ยม


20

ฉันรู้สึกทึ่งกับการออกแบบกราฟิกนี้จาก New York Times ซึ่งในแต่ละรัฐของสหรัฐจะถูกแสดงด้วยตารางในตาราง ฉันสงสัยว่าพวกเขาวางสี่เหลี่ยมด้วยมือหรือจริง ๆ แล้วพบว่าตำแหน่งที่เหมาะสมของสี่เหลี่ยม (ภายใต้คำจำกัดความบางอย่าง) เพื่อเป็นตัวแทนของตำแหน่งของรัฐที่อยู่ติดกัน

กราฟิคตรวจสอบประวัติปืนจาก New York Times

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

รหัสของคุณจะแสดงรายการคู่พิกัด X และ Y ที่ลอยได้จาก 0.0 ถึง 100.0 (รวม) ในรูปแบบที่สะดวกและจะส่งออกพิกัดจำนวนเต็มแบบไม่ลบของหน่วยสี่เหลี่ยมในตารางที่วางอย่างเหมาะสมเพื่อแสดงข้อมูล รักษาความสงบเรียบร้อย ในกรณีที่การจัดเรียงสี่เหลี่ยมหลายแบบนั้นดีที่สุดคุณสามารถส่งออกการจัดเรียงที่เหมาะสมที่สุดได้ จะได้รับพิกัดระหว่าง 1 ถึง 100 คู่

นี่คือรหัสกอล์ฟรหัสที่สั้นที่สุดชนะ

ตัวอย่าง:

การป้อนข้อมูล: [(0.0, 0.0), (1.0, 1.0), (0.0, 1.0), (1.0, 0.0)]

นี่เป็นวิธีที่ง่าย จุดศูนย์กลางของช่องสี่เหลี่ยมในตารางของเราอยู่ที่ 0.0, 1.0, 2.0, และอื่น ๆ ดังนั้นรูปร่างเหล่านี้จึงถูกวางไว้อย่างสมบูรณ์แบบที่ศูนย์กลางของช่องสี่เหลี่ยมในรูปแบบนี้:

21
03

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

[(0, 0), (1, 1), (0, 1), (1, 0)]

การป้อนข้อมูล: [(2.0, 2.1), (2.0, 2.2), (2.1, 2.0), (2.0, 1.9), (1.9, 2.0)]

ในกรณีนี้รูปร่างทั้งหมดอยู่ใกล้กับศูนย์กลางของจัตุรัสที่ (2, 2) แต่เราจำเป็นต้องผลักมันออกไปเพราะสองสี่เหลี่ยมไม่สามารถอยู่ในตำแหน่งเดียวกันได้ การลดระยะห่างจากเซนทรอยด์ของรูปร่างไปยังศูนย์กลางของสี่เหลี่ยมจัตุรัสซึ่งแสดงถึงรูปแบบนี้:

 1
402
 3

[(2, 2), (2, 3), (3, 2), (2, 1), (1, 2)]ดังนั้นการส่งออกของคุณควรจะ

กรณีทดสอบ:

[(0.0, 0.0), (1.0, 1.0), (0.0, 1.0), (1.0, 0.0)] -> [(0, 0), (1, 1), (0, 1), (1, 0)]
[(2.0, 2.1), (2.0, 2.2), (2.1, 2.0), (2.0, 1.9), (1.9, 2.0)] -> [(2, 2), (2, 3), (3, 2), (2, 1), (1, 2)]
[(94.838, 63.634), (97.533, 1.047), (71.954, 18.17), (74.493, 30.886), (19.453, 20.396), (54.752, 56.791), (79.753, 68.383), (15.794, 25.801), (81.689, 95.885), (27.528, 71.253)] -> [(95, 64), (98, 1), (72, 18), (74, 31), (19, 20), (55, 57), (80, 68), (16, 26), (82, 96), (28, 71)]
[(0.0, 0.0), (0.1, 0.0), (0.2, 0.0), (0.0, 0.1), (0.1, 0.1), (0.2, 0.1), (0.0, 0.2), (0.1, 0.2), (0.2, 0.2)] -> [(0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1), (0, 2), (1, 2), (2, 2)]
[(1.0, 0.0), (1.0, 0.1), (1.0, 0.2), (1.0, 0.3)] -> [(1, 0), (0, 0), (2, 0), (1, 1)] or [(1, 0), (2, 0), (0, 0), (1, 1)]
[(3.75, 3.75), (4.25, 4.25)] -> [(3, 4), (4, 4)] or [(4, 3), (4, 4)] or [(4, 4), (4, 5)] or [(4, 4), (5, 4)]

ระยะทางโดยรวมจากเซนทรอยด์ของรูปร่างไปยังศูนย์กลางของช่องสี่เหลี่ยมที่แสดงถึงแต่ละกรณี (โปรดแจ้งให้เราทราบหากคุณพบข้อผิดพลาด!):

0.0
3.6
4.087011
13.243299
2.724791
1.144123

แค่เล่น ๆ:

นี่คือตัวแทนของศูนย์กลางทางภูมิศาสตร์ของสหรัฐอเมริกาที่ต่อเนื่องกันในรูปแบบการป้อนข้อมูลของเราโดยประมาณตามขนาดที่ Times ใช้:

[(15.2284, 3.1114), (5.3367, 3.7096), (13.0228, 3.9575), (2.2198, 4.8797), (7.7802, 5.5992), (20.9091, 6.6488), (19.798, 5.5958), (19.1941, 5.564), (17.023, 1.4513), (16.6233, 3.0576), (4.1566, 7.7415), (14.3214, 6.0164), (15.4873, 5.9575), (12.6016, 6.8301), (10.648, 5.398), (15.8792, 5.0144), (13.2019, 2.4276), (22.3025, 8.1481), (19.2836, 5.622), (21.2767, 6.9038), (15.8354, 7.7384), (12.2782, 8.5124), (14.1328, 3.094), (13.0172, 5.3427), (6.142, 8.8211), (10.0813, 6.6157), (3.3493, 5.7322), (21.3673, 7.4722), (20.1307, 6.0763), (7.5549, 3.7626), (19.7895, 7.1817), (18.2458, 4.2232), (9.813, 8.98), (16.8825, 6.1145), (11.0023, 4.2364), (1.7753, 7.5734), (18.8806, 6.3514), (21.3775, 6.6705), (17.6417, 3.5668), (9.9087, 7.7778), (15.4598, 4.3442), (10.2685, 2.5916), (5.3326, 5.7223), (20.9335, 7.6275), (18.4588, 5.0092), (1.8198, 8.9529), (17.7508, 5.4564), (14.0024, 7.8497), (6.9789, 7.1984)]

ในการรับสิ่งเหล่านี้ฉันได้รับพิกัดจากรายการที่สองในหน้านี้และใช้0.4 * (125.0 - longitude)สำหรับพิกัด X ของเราและ0.4 * (latitude - 25.0)สำหรับพิกัด Y ของเรา นี่คือสิ่งที่ดูเหมือนจะลงจุด:

พล็อตของศูนย์กลางทางภูมิศาสตร์ของสหรัฐอเมริกาที่ต่อเนื่องกัน

คนแรกที่ใช้เอาต์พุตจากโค้ดของพวกเขาด้วยพิกัดด้านบนเป็นอินพุตเพื่อสร้างไดอะแกรมที่มีกำลังสองจริงได้รับการตบหลัง!


ผมเชื่อว่าจุดสุดท้ายในตัวอย่างที่สองของคุณควรจะไม่(1, 2) (1, 1)
ทิม Pederick

เยี่ยมมากขอบคุณ!
ลุค

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

PS: คุณได้ทดสอบจริง ๆ ว่าแผนที่ที่กำหนดนั้นเป็นผลลัพธ์ที่ถูกต้องของปัญหาการเพิ่มประสิทธิภาพของคุณหรือไม่ เพราะสังหรณ์ใจฉันไม่คิดว่ามันเป็น
ข้อบกพร่อง

ฉันสามารถเพิ่มระยะทางทั้งหมด แผนที่ the Times ที่ใช้นั้นแทบจะไม่เหมาะสมที่สุด
ลุค

คำตอบ:


3

Mathematica, 473 ไบต์

f@p_:=(s=Flatten@Round@p;v=Array[{x@#,y@#}&,n=Length@p];
  Do[w=Flatten[{g@#,h@#}&/@(b=Flatten@Position[p,x_/;Norm[x-p[[i]]]<=2,{1}])];f=Total[Norm/@(p-v)]+Total[If[#1==#2,1*^4,0]&@@@v~Subsets~{2}]/.Flatten[{x@#->g@#,y@#->h@#}&@@@w]/.Thread[Flatten@v->s];
    c=w∈Integers&&And@@MapThread[Max[#-2,0]<=#2<=Min[#+2,100]&,{Flatten@p[[b]],w}];s=Flatten@ReplacePart[s~Partition~2,Thread[b->Partition[w/.Last@Quiet@NMinimize[{f,c},w,MaxIterations->300],2]]]
    ,{i,n}]~Do~{2};s~Partition~2)

ก่อนเล่นกอล์ฟ:

f[p_]:=(n=Length@p;s=Flatten@Round@p;v=Array[{x[#],y[#]}&,n];
  Do[
    v2=Flatten[{x2[#],y2[#]}&/@(b=Flatten@Position[p,x_/;Norm[x-p[[i]]]<=2,{1}])];
    f2=Total[Norm/@(p-v)]+Total[If[#1==#2,1*^4,0]&@@@Subsets[v,{2}]]/.Flatten[{x[#]->x2[#],y[#]->y2[#]}&@@@v2]/.Thread[Flatten@v->s];
    c2=v2∈Integers&&And@@MapThread[Max[#-2,0]<=#2<=Min[#+2,100]&,{Flatten@p[[b]],v2}];
    s=Flatten@ReplacePart[s~Partition~2,Thread[b->Partition[v2/.Last@Quiet@NMinimize[{f2,c2},v2,MaxIterations->300],2]]];
    ,{i,n}]~Do~{2};
  s~Partition~2)

คำอธิบาย :

ปัญหาการปรับให้เหมาะสมนี้ไม่ยากที่จะอธิบายใน Mathematica ได้รับรายชื่อของจุดpของความยาวn,

  • ตัวแปรคือx[i]และy[i]: v=Array[{x[#],y[#]}&,n],
  • ฟังก์ชั่นเพื่อลดคือผลรวมของการกระจัดนี้f=Total[Norm/@(p-v)],
  • ข้อ จำกัด c=Flatten[v]∈Integers&&And@@(Or@@Thread[#1!=#2]&@@@Subsets[v,{2}])คือ:

และNMinimize[{f,cons},v,MaxIterations->Infinity]จะให้ผลลัพธ์ แต่น่าเสียดายที่รูปแบบตรงไปตรงมาดูเหมือนซับซ้อนเกินไปที่จะมาบรรจบกัน

เมื่อต้องการแก้ไขปัญหาของความซับซ้อนมีการใช้เทคนิคสองอย่าง:

  • "ปฏิสัมพันธ์" ขนาดใหญ่If[#1==#2,1*^4,0]&ใช้เพื่อหลีกเลี่ยงการปะทะกันระหว่างจุด
  • แทนที่จะปรับตัวแปรทั้งหมดในเวลาเดียวกันเราปรับให้เหมาะสมทุกจุดกับเพื่อนบ้านในทางกลับกัน

เราเริ่มจากการเดาเบื้องต้นโดยการปัดเศษคะแนน เมื่อการปรับให้เหมาะสมเสร็จสิ้นทีละตัวการชนนั้นคาดว่าจะได้รับการแก้ไขและมีการจัดการที่เหมาะสมที่สุด

ทางออกสุดท้ายคือดีอย่างน้อยถ้าไม่เหมาะสม (ฉันเชื่อ:P)


ผลลัพธ์ :

ผลลัพธ์ของJust for funแสดงอยู่ด้านล่าง จุดสีเขียวเข้มคืออินพุตสี่เหลี่ยมสีเทาเป็นเอาท์พุตและเส้นสีดำแสดงการกระจัด

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

ผลรวมของการกระจัดเป็น19.4595 และการแก้ปัญหาคือ

{{15,3},{5,4},{13,4},{2,5},{8,6},{21,6},{20,5},{19,5},{17,1},{17,3},{4,8},{14,6},{15,6},{13,7},{11,5},{16,5},{13,2},{22,8},{19,6},{21,7},{16,8},{12,9},{14,3},{13,5},{6,9},{10,7},{3,6},{22,7},{20,6},{8,4},{20,7},{18,4},{10,9},{17,6},{11,4},{2,8},{19,7},{22,6},{18,3},{10,8},{15,4},{10,3},{5,6},{21,8},{18,5},{2,9},{18,6},{14,8},{7,7}}

ฮา! ฉันแค่คิดว่าจะสร้างไดอะแกรมแบบสุดท้าย ทำได้ดี.
ทิม Pederick

การทำงานที่ดี. วิธีแก้ปัญหาของคุณไปยังแผนที่ของสหรัฐอเมริกานั้นเหมาะสมกับฉันมากที่สุด
ลุค

2

Python 3, 877 ไบต์

นี่ไม่ใช่การใช้งานที่ถูกต้อง มันล้มเหลวในวันที่สองของ "กรณีทดสอบเพิ่มเติม" ซึ่งผลิตโซลูชันที่มีระยะทางรวม 13.5325 ครั้งซึ่งโซลูชันดังกล่าวมีความต้องการเพียง 13.2433 เท่านั้น สิ่งที่ซับซ้อนกว่านั้นคือความจริงที่ว่าการติดตั้งกอล์ฟของฉันไม่ตรงกับสิ่งที่ฉันไม่ได้เขียน ...

อย่างไรก็ตามไม่มีใครตอบได้และนี่เป็นความท้าทายที่น่าสนใจเกินกว่าจะผ่านพ้นไปได้ นอกจากนี้ฉันยังมีรูปภาพที่สร้างขึ้นจากข้อมูล USA ดังนั้นจึงมี

อัลกอริทึมเป็นดังนี้:

  1. กดจุดทั้งหมดเป็นพิกัดจำนวนเต็มที่ใกล้ที่สุด (ซึ่งต่อไปจะเรียกว่า "สี่เหลี่ยม")
  2. ค้นหาสี่เหลี่ยมที่มีจำนวนคะแนนมากที่สุด
  3. ค้นหาการกระจายจุดที่มีต้นทุนต่ำที่สุดไปยังพื้นที่ใกล้เคียงที่มีพื้นที่เก้าตารางเมตรของจุดนี้ไม่รวมช่องสี่เหลี่ยมที่ได้ดำเนินการแล้วในขั้นตอนที่ 2
    • การแจกจ่ายซ้ำจะถูก จำกัด ที่หนึ่งจุดต่อตารางเว้นแต่ว่าจะไม่ให้เพียงพอสี่เหลี่ยม (แม้ว่าถึงตอนนั้นเพียงจุดเดียวจะยังคงอยู่ในตารางนี้ )
  4. ทำซ้ำจากขั้นตอนที่ 2 จนกว่าจะไม่มีสี่เหลี่ยมจัตุรัสมีมากกว่าหนึ่งจุด
  5. ค้นหาจุดเดิมแต่ละจุดตามลำดับและส่งออกกำลังสองตามลำดับ

ฉันไม่มีข้อพิสูจน์ในแง่ดีที่สุดสำหรับส่วนใด ๆ ของอัลกอริทึมนี้ แต่เป็นข้อกังขาอย่างมากว่ามันจะให้ผลลัพธ์ที่ "ดีมาก" ฉันคิดว่านั่นคือสิ่งที่เราเรียกว่า "อัลกอริทึมฮิวริสติก" ย้อนกลับไปในวันเดียวของฉัน ... !

l=len
I,G,M=-1,101,150
d=lambda x,y,X,Y:abs(x-X+1j*(y-Y))
N=(0,0),(I,0),(0,I),(1,0),(0,1),(I,I),(1,I),(1,1),(I,I)
n=lambda p,e:[(x,y)for(x,y)in(map(sum,zip(*i))for i in zip([p]*9,N))if(x,y)not in e and I<x<G and I<y<G]
def f(p):
 g={};F=[];O=[I]*l(p)
 for P in p:
  z=*map(round,P),
  if z in g:g[z]+=[P]
  else:g[z]=[P]
 while l(g)<l(p):
  L,*P=0,
  for G in g:
   if l(g[G])>l(P):L,P=G,g[G]
  o=n(L,F);h=l(o)<l(P);c=[[d(*q,*r)for r in o]for q in P];r={}
  while l(r)<l(c):
   A=B=C=M;R=S=0
   while R<l(c):
    if R not in r:
     z=min(c[R])
     if z<A:B,A=R,z;C=c[R].index(A)
    R+=1
   while S<l(c):
    if S==B:
     v=0
     while v<l(c[S]):
      if v!=C:c[S][v]=M
      v+=1
    elif C<1or not h:c[S][C]=M
    S+=1
   r[B]=C
  for q in r:
   x,y=P[q],o[r[q]]
   if y==L or y not in g:g[y]=[x]
   else:g[y]+=[x]
  F+=[L]
 for G in g:
  O[p.index(g[G][0])]=G
 return O

และผลลัพธ์ของการรันบนข้อมูล USA (ด้วยฟังก์ชันยูทิลิตี้ที่เปลี่ยนผลลัพธ์เป็น SVG): แผนผังแผนผังของสหรัฐอเมริกาที่ต่อเนื่องกัน

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


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

จากความอยากรู้คุณทำแผนที่ในประเทศสหรัฐอเมริกาทั้งหมดเท่าไหร่?
Tom Carpenter

ฉันน่าจะถามคำถามตัวเองว่า ... เพราะมันแสดงให้ฉันเห็นว่าการเล่นกอล์ฟของฉันนั้นแย่กว่าที่ฉันคิด ฉบับดั้งเดิมของฉันไม่ได้รับการอวดโฉมได้ใน 20.9164 แต่รุ่นที่ฉันโพสต์ให้ฉันไว้ 20.9987 * ถอนหายใจ *
ทิม Pederick

1

MATLAB, 316 343 326 ไบต์

อันนี้เป็นงานที่กำลังดำเนินการ - มันไม่เร็ว แต่สั้น ดูเหมือนว่าจะผ่านกรณีทดสอบส่วนใหญ่ ในขณะนี้อินพุทเพื่อความสนุกของแผนที่กำลังทำงาน แต่ขณะนี้ยังคงดำเนินต่อไปหลังจาก 10 นาทีดังนั้น ...

function p=s(a)
c=ceil(a');a=a(:,1)+j*a(:,2);[~,p]=r(a,c,[],Inf);p=[real(p),imag(p)];end
function [o,p]=r(a,c,p,o)
if ~numel(c)
o=sum(abs(p-a));else
x=c(1)+(-1:1);y=c(2)+(-1:1);P=p;
for X=1:3
for Y=1:3
Q=x(X)+j*y(Y);if(x(X)>=0)&(y(Y)>=0)&all(Q~=P)
[O,Q]=r(a,c(:,2:end),[P;Q],o);
if(O<o) o=O;p=Q;disp(o);end
end;end;end;end;end

และในรูปแบบที่อ่านง่ายขึ้น:

function p=squaremap(a)
%Input format: [2.0, 2.1;2.0, 2.2;2.1, 2.0;2.0, 1.9;1.9, 2.0]

    c=ceil(a'); %Convert each point to the next highest integer centre
    a=a(:,1)+j*a(:,2); %Convert each 2D point into a complex number
    [~,p]=r(a,c,[],Inf); %Recurse!
    p=[real(p),imag(p)];
end

function [o,p]=r(a,c,p,o)
    if ~numel(c) %If we are as deep as we can go
        o=sum(abs(p-a)); %See what our overall distance is
    else
        x=c(1)+(-1:1);y=c(2)+(-1:1); %For each point we try 9 points, essentially a 3x3 square
        P=p;
        for X=1:3;
            for Y=1:3
                %For each point
                Q=x(X)+j*y(Y); %Covert to a complex number
                if(x(X)>=0)&(y(Y)>=0)&all(Q~=P) %If the point is not negative and has not already been used this iteration
                    [O,Q]=r(a,c(:,2:end),[P;Q],o); %Otherwise iterate further
                    if(O<o) o=O;p=Q;end %Keep updating the smallest path and list of points we have found
                end
            end
        end
    end
end

รูปแบบอินพุตที่คาดว่าจะเป็นอาร์เรย์ MATLAB เช่น:

[2.0, 2.1;2.0, 2.2;2.1, 2.0;2.0, 1.9;1.9, 2.0]

ซึ่งค่อนข้างใกล้เคียงกับรูปแบบในคำถามซึ่งอนุญาตให้ใช้งานได้นาน

เอาต์พุตอยู่ในรูปแบบเดียวกับอินพุตอาร์เรย์ที่ดัชนีใด ๆ ที่สอดคล้องกับจุดเดียวกันทั้งอินพุตและเอาต์พุต


อืม 8 ชั่วโมงและยังคงทำงานอยู่บนแผนที่หนึ่ง ... โซลูชันนี้รับประกันว่าจะหาสิ่งที่ดีที่สุด แต่ทำได้โดยใช้กำลังดุร้ายดังนั้นจึงใช้เวลานานมาก

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

แผนที่

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