정사각형 구멍을 정사각형 구멍에 넣기


20

뉴욕 타임즈에서이 그래픽을 디자인 한 것에 흥미를 느꼈습니다. 뉴욕 타임즈는 각 미국 주가 그리드의 사각형으로 표시됩니다. 나는 그들이 손으로 정사각형을 배치했는지 또는 실제로 인접 상태의 위치를 ​​나타내는 정사각형 (일부 정의에서)의 최적 배치를 찾았는지 궁금했습니다.

뉴욕 타임즈에서 총 배경 확인 그래픽

코드는 상태 (또는 다른 임의의 2 차원 모양)를 나타 내기 위해 정사각형을 최적으로 배치하는 문제의 작은 부분을 차지할 것입니다. 구체적으로, 우리는 이미 모양의 모든 지리적 중심 또는 중심 을 가지고 있다고 가정합니다 편리한 형식이며, 이와 같은 다이어그램에서 데이터의 최적 표현은 셰이프 중심에서 사각형을 나타내는 중심까지의 거리가 각각 최소 하나의 사각형으로 최소 인 형식입니다. 가능한 위치.

코드는 편리한 형식으로 0.0에서 100.0까지의 부동 소수점 X 및 Y 좌표의 고유 쌍 목록을 가져오고 데이터를 표현하기 위해 최적으로 배치 된 격자에 단위 사각형의 음이 아닌 정수 좌표를 출력합니다 순서를 유지합니다. 여러 정사각형 배열이 최적 인 경우 최적 배열을 출력 할 수 있습니다. 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

재미로:

다음은 대략 시간이 사용 된 규모로 입력 형식으로 인접한 미국의 지리적 중심을 나타냅니다.

[(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)합니다.
Tim Pederick

잘 잡아라, 고마워!
Luke

각 테스트 케이스에서 모든 거리의 총계를 게시 할 수 있습니까? 이것은 확실히 사소한 문제이므로 대체 솔루션이 실제로 최적인지 확인할 수 있습니다.
flawr

추신 : 실제로 주어진지도가 실제로 최적화 문제의 유효한 결과인지 테스트 했습니까? 직관적으로 생각하지 않기 때문입니다.
flawr

총 거리를 추가 할 수 있습니다. Times가 사용한지도는 거의 확실하지 않습니다.
Luke

답변:


3

매스 매 티카, 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

잘 했어. 직관적으로 미국지도에 대한 귀하의 솔루션은 나에게 최적입니다.
Luke

2

파이썬 3, 877 바이트

이것은 올바른 구현 이 아닙니다 . 두 번째 "추가 테스트 사례"에서 실패하여 전체 거리가 13.5325 인 솔루션이 생성되며 여기에서 제공된 솔루션은 13.2433 만 필요합니다. 더 복잡한 문제는 내 골프 구현이 내가 처음으로 작성한 ungolfed와 일치하지 않는다는 사실입니다 ...

그러나 아무도 대답하지 않았으며, 이것은 과거를 빠져 나가기에는 너무 흥미로운 도전입니다. 또한 미국 데이터에서 생성 된 그림이 있습니다.

알고리즘은 다음과 같습니다.

  1. 모든 점을 가장 가까운 정수 좌표 (이하 "사각형")로 밉니다.
  2. 포인트 수가 가장 많은 정사각형을 찾으십시오.
  3. 2 단계에서 이미 처리 된 사각형을 제외하고이 점을이 사각형의 9 평방 이웃에 가장 저렴한 재분배를 찾으십시오.
    • 그만큼 사각형을 제공하지 않습니다하지 않는 재분배는 (그렇다하더라도 있지만, 단 하나의 지점에 남아, 평방 당 하나의 포인트로 제한 광장).
  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로 바꾸는 유틸리티 기능 덕분에) : 인접한 미국의 개략도

이것은 ungolfed 코드가 생성 한 것보다 약간 나쁩니다. 가장 눈에 띄는 차이점은 가장 오른쪽에있는 정사각형이 더 왼쪽에있는 것입니다.


당신은 뒷면에 팻을 얻을! Times의 다이어그램과 비슷하게 보이도록 경도의 스케일링을 작업 해야하는 것처럼 보입니다.
Luke

호기심에서 미국지도의 총 거리는 얼마입니까?
Tom Carpenter

아마도 내 자신의 질문을했을 것입니다 ... 내 골프 구현이 생각보다 나쁘다는 것을 보여 주었 기 때문입니다. 내 원래, ungolfed 버전은 20.9164에 그것을 얻었지만 내가 게시 한 버전은 20.9987을 주었다. * sigh *
Tim 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.