Kare delikleri kare deliklere koymak


20

Bu grafiğin, her ABD eyaletinin bir ızgaradaki bir kare ile temsil edildiği New York Times'dan tasarımı ilgimi çekti. Kareleri elle yerleştirip yerleştirmediklerini ya da bitişik durumların konumlarını temsil etmek için gerçekten bir kareler (bazı tanımların altında) yerleştirip yerleştirmediklerini merak ettim.

New York Times silah arka plan onay grafiği

Kodunuz, durumları (veya diğer rasgele iki boyutlu şekilleri) temsil etmek için kareleri en uygun şekilde yerleştirme zorluğunun küçük bir bölümünü ele alacaktır. Özellikle, şekillerdeki tüm coğrafi merkezlere veya centroidlere sahip olduğumuzu varsayacaktır . uygun bir formattır ve böyle bir diyagramdaki verilerin en uygun şekilde temsil edilmesi, şekillerin merkezlerinden, onları temsil eden karelerin merkezlerine olan toplam mesafenin en az olduğu, her birinde en fazla bir kare olduğu olası konum.

Kodunuz, herhangi bir uygun biçimde 0.0 ila 100.0 (dahil) arasındaki kayan nokta X ve Y koordinatlarının benzersiz çiftlerinin bir listesini alır ve verileri temsil etmek için en uygun şekilde yerleştirilmiş bir ızgarada birim karelerinin negatif olmayan tam sayı koordinatlarını verir , düzeni koruyor. Birden çok kare düzenlemesinin en uygun olduğu durumlarda, optimum düzenlemelerden herhangi birini çıktı alabilirsiniz. 1 ile 100 çift arasında koordinat verilecektir.

Bu kod golf, en kısa kod kazanır.

Örnekler:

Giriş: [(0.0, 0.0), (1.0, 1.0), (0.0, 1.0), (1.0, 0.0)]

Bu kolay bir soru. Izgaramızdaki karelerin merkezleri 0.0, 1.0, 2.0 vb. Şeklindedir, bu nedenle bu şekiller zaten bu modeldeki karelerin merkezlerine mükemmel bir şekilde yerleştirilmiştir:

21
03

Dolayısıyla çıktınız tam olarak bu koordinatlar olmalı, ancak tamsayı olarak, seçtiğiniz bir biçimde olmalıdır:

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

Giriş: [(2.0, 2.1), (2.0, 2.2), (2.1, 2.0), (2.0, 1.9), (1.9, 2.0)]

Bu durumda, tüm şekiller (2, 2) 'deki karenin merkezine yakındır, ancak onları itmek zorundayız çünkü iki kare aynı konumda olamaz. Bir şeklin centroidinden onu temsil eden karenin merkezine olan mesafeyi en aza indirmek bize bu deseni verir:

 1
402
 3

Yani çıktınız olmalı [(2, 2), (2, 3), (3, 2), (2, 1), (1, 2)].

Test senaryoları:

[(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)]

Şekillerin sentroidlerinden her durumda kendilerini temsil eden karelerin merkezlerine olan toplam mesafe (herhangi bir hatayı tespit ederseniz lütfen bize bildirin!):

0.0
3.6
4.087011
13.243299
2.724791
1.144123

Sadece eğlence için:

İşte bitişik ABD'nin coğrafi merkezlerinin girdi biçimimizde, kabaca Times'ın kullandığı ölçekte bir temsili:

[(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)]

Bunları elde etmek için, bu sayfadaki ikinci listeden koordinatları aldım ve 0.4 * (125.0 - longitude)X koordinatımız ve 0.4 * (latitude - 25.0)Y koordinatımız için kullandım. Çizilen şuna benzer:

Bitişik Amerika Birleşik Devletleri coğrafi merkezlerinin arsa.

Kodlarından çıktıyı yukarıdaki koordinatlarla birlikte kullanan ilk kişi, gerçek karelerle bir diyagram oluşturmak için girdi olarak arkada bir pat alır!


Ben senin ikinci örnekteki son nokta olması gerektiğine inanıyoruz (1, 2), değil (1, 1).
Tim Pederick

İyi yakaladın, teşekkürler!
Luke

Lütfen her test senaryosundaki tüm mesafelerin toplamını da gönderebilir misiniz? Bu kesinlikle önemsiz bir sorundur ve bu da alternatif bir çözümün gerçekten de optimal olup olmadığını doğrulamamıza izin verecektir.
Kusur

Not: Verilen haritanın aslında optimizasyon probleminizin geçerli bir sonucu olduğunu test ettiniz mi? Çünkü sezgisel olarak bunun olduğunu düşünmüyorum.
Kusur

Toplam mesafeleri ekleyebilirim. Times'ın kullandığı harita neredeyse kesinlikle optimal değil.
Luke

Yanıtlar:


3

Mathematica, 473 bayt

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)

Golf oynamadan önce:

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)

Açıklama :

Bu optimizasyon problemini Mathematica'da tanımlamak zor değil. pUzunluk noktalarının bir listesi verildiğinde n,

  • değişkenlerdir x[i]ve y[i]: v=Array[{x[#],y[#]}&,n],
  • en aza indirmek için işlev değiştirmeler toplamı olan: f=Total[Norm/@(p-v)],
  • kısıtlamaları şunlardır: c=Flatten[v]∈Integers&&And@@(Or@@Thread[#1!=#2]&@@@Subsets[v,{2}]).

Ve NMinimize[{f,cons},v,MaxIterations->Infinity]sonuç verecek. Ancak ne yazık ki, böyle düz bir plan, birleşmek için çok karmaşık görünüyor.

Karmaşıklık sorununu çözmek için iki teknik benimsenmiştir:

  • büyük bir "etkileşim", If[#1==#2,1*^4,0]&noktalar arasında çarpışmayı önlemek için kullanılır.
  • tüm değişkenleri aynı anda optimize etmek yerine, her noktayı komşularıyla sırayla optimize ederiz.

Noktaları yuvarlayarak ilk tahminden başlıyoruz. Optimizasyonlar tek tek yapıldığında, çarpışmaların çözülmesi beklenir ve optimize edilmiş bir düzenleme yapılır.

Nihai çözüm, optimal değilse, en azından iyidir. (İnanıyorum :P)


Sonuç :

Just for fun'un sonucu aşağıda gösterilmiştir. Koyu yeşil noktalar girdiler, gri kareler çıktılardır ve siyah çizgiler yer değiştirmeleri gösterir.

resim açıklamasını buraya girin

Deplasmanların toplamı 19.4595'tir . Ve çözüm

{{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}}

Ha! Sadece sonuncusu gibi bir diyagram yapmayı düşünüyordum. Aferin.
Tim Pederick

İyi iş. Sezgisel olarak, ABD haritasına çözümünüz benim için en uygun görünüyor.
Luke

2

Python 3, 877 bayt

Bu doğru bir uygulama değil . "Daha fazla test vakası" nın ikincisinde başarısız olur ve toplam 13.5325 mesafeye sahip bir çözüm üretir, burada sağlanan çözüm sadece 13.2433'e ihtiyaç duyar. Daha da karmaşık olan konular, golf uygulamamın ilk yazdığım ungolfed uygulamayla eşleşmemesi ...

Ancak, başka kimse cevap vermedi ve bu, geçmişin kaymasına izin vermek için çok ilginç bir meydan okuma. Ayrıca, ABD verilerinden oluşturulan bir resmim var, işte bu.

Algoritma şöyle bir şeydir:

  1. Tüm noktaları en yakın tamsayı koordinatlarına (bundan sonra "kare" olarak adlandırılacaktır) itin.
  2. En fazla puana sahip kareyi bulun.
  3. Adım 2'de zaten işlenmiş olan tüm kareler hariç, bu noktaların dokuz kare mahalleye en düşük maliyetli yeniden dağıtımını bulun.
    • Yeniden dağıtım, yeterli kareler sağlamadığı sürece kare başına bir nokta ile sınırlıdır (o zaman bile, bu meydanda sadece bir nokta kalacaktır ).
  4. Hiçbir karenin birden fazla noktası bulunmayana kadar adım 2'den itibaren tekrarlayın.
  5. Orijinal noktaların her birini sırayla bulun ve sırasıyla karelerini çıktılayın.

Bu algoritmanın herhangi bir kısmı için kesinlikle bir iyimserlik kanıtım yok, sadece "oldukça iyi" sonuçlar sağlayacağından şüphe duyuyorum. Uni günlerimde "sezgisel algoritma" dediğimiz şey budur ...!

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

Ve bunu ABD verilerinde çalıştırmanın sonucu (sonuçları SVG'ye dönüştüren bir yardımcı program işlevi sayesinde): Bitişik Amerika Birleşik Devletleri'nin şematik haritası

Bu, çözülmemiş kodun ürettiğinden biraz daha kötüdür; görünen tek fark, en sağdaki en üstteki karenin daha iyi olanın solunda bir tane daha olmasıdır.


Arkada bir pat var! Görünüşe göre bu, Times'ın şemasına biraz benzemek için boylamın ölçeklendirilmesi üzerinde çalışmam gerekiyor.
Luke

Merak ettikten sonra ABD haritanız için hangi mesafeyi alıyorsunuz?
Tom Carpenter

Muhtemelen kendime bu soruyu sormalıydım ... çünkü bana golf sahamın düşündüğümden daha kötü olduğunu gösterdi. Orijinal, ungolfed versiyonum bunu 20.9164'te aldı, ancak gönderdiğim versiyon bana 20.9987 verdi. * iç
çeker

1

MATLAB, 316 343 326 bayt

Bu devam eden bir çalışma - hızlı değil, ama kısa. Test vakalarının çoğunu geçiyor gibi görünüyor. Şu anda haritanın eğlenceli girişi için bir tane çalışıyor, ancak hala 10 dakika sonra gidiyor, bu yüzden ...

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

Ve biraz daha okunabilir bir biçimde:

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

Giriş formatının bir MATLAB dizisi olması beklenir, örneğin:

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

Hangi soru biraz biraz izin veren biçimine oldukça yakın.

Çıktı, girdi ile aynı formattadır; belirli bir dizinin hem girdi hem de çıktıdaki aynı noktaya karşılık geldiği bir dizidir.


Hmm, 8 saat ve hala haritada bir tane çalışıyor ... bu çözüm en uygun bulmayı garanti ediyor, ancak kaba kuvvetle yapıyor, bu yüzden çok uzun zaman alıyor.

Daha hızlı olan başka bir çözüm buldum, ancak diğer cevap gibi test durumlarından birinde en uygun olanı bulamıyor. İlginçtir, diğer çözümüm için aldığım harita (gönderilmedi) aşağıda gösterilmektedir. Toplam mesafe 20.72'dir.

harita

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.