Programing

서로 다른 크기의 사각형을 가능한 가장 작은 사각형으로 압축하는 데 어떤 알고리즘을 사용할 수 있습니까?

lottogame 2020. 3. 27. 07:58
반응형

서로 다른 크기의 사각형을 가능한 가장 작은 사각형으로 압축하는 데 어떤 알고리즘을 사용할 수 있습니까?


가능한 한 가장 작은 공간에 포장 해야하는 직사각형 객체가 많이 있습니다 (이 공간의 크기는 2의 거듭 제곱이어야합니다).

항목을 가능한 한 주어진 공간에 포장하는 다양한 포장 알고리즘을 알고 있지만이 경우 공간이 얼마나 커야하는지 알고리즘이 필요합니다.

예를 들어 다음 사각형이 있다고 가정 해보십시오.

  • 128 * 32
  • 128 * 64
  • 64 * 32
  • 64 * 32

그들은 128 * 128 공간으로 포장 될 수 있습니다

 _________________
| 128 * 32 |
| ________________ |
| 128 * 64 |
| |
| |
| ________________ |
| 64 * 32 | 64 * 32 |
| _______ | ________ |

그러나 160 * 32 및 64 * 64도있는 경우 256 * 128 공간이 필요합니다.

 ________________________________
| 128 * 32 | 64 * 64 | 64 * 32 |
| ________________ | | _______ |
| 128 * 64 | | 64 * 32 |
| | _______ | _______ |
| | |
| ________________ | ___ |
| 160 * 32 | |
| ____________________ | ___________ |

많은 사각형을 포장하고 컨테이너에 필요한 크기 (2의 거듭 제곱, 각 치수에 대해 주어진 최대 크기 이내)를 결정할 수있는 알고리즘은 무엇입니까?


빠르고 더러운 첫 번째 패스 솔루션은 다른 방법이 없다면 비교해 보는 것이 좋습니다.

욕심 배치가 큰 것에서 작은 것.

가장 큰 직사각형을 포장 된 영역에 넣습니다. 어디에도 맞지 않을 경우 가능한 한 팩 영역을 확장하는 곳에 배치하십시오. 가장 작은 사각형으로 끝날 때까지 반복하십시오.

전혀 완벽하지는 않지만 쉽고 좋은 기준입니다. 그것은 여전히 ​​원래의 예를 완벽하게 포장하고 두 번째에도 동등한 대답을 줄 것입니다.


솔루션에 대한 설문 조사 는 ARC 프로젝트의이 페이지를 참조하십시오. 구현 복잡성 / 시간과 최적 성 사이에는 상충 관계가 있지만 선택할 수있는 광범위한 알고리즘이 있습니다.

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

  1. FFDH (First-Fit 감소 높이) 알고리즘
    FFDH는 R이 맞는 첫 번째 레벨에서 다음 항목 R (증가하지 않는 높이)을 압축합니다. R을 수용 할 수있는 레벨이 없으면 새 레벨이 작성됩니다.
    FFDH의 시간 복잡도 : O (n · log n).
    근사 비율 : FFDH (I) <= (17/10) · OPT (I) +1; 17/10의 점근 적 경계는 빡빡합니다.

  2. NFDH (Next-Fit Decreeasing Height) 알고리즘
    NFDH는 R이 맞는 경우 다음 레벨 R을 현재 레벨에서 증가하지 않는 높이로 압축합니다. 그렇지 않으면 현재 레벨이 "닫히고"새 레벨이 작성됩니다.
    시간 복잡도 : O (n · log n).
    근사 비율 : NFDH (I) <= 2 · OPT (I) +1; 2의 점근 적 경계는 빡빡합니다.

  3. BFDH (Best-Fit Decineasing Height) 알고리즘
    BFDH는 R을 수용 할 수있는 나머지 수평 공간이 최소 인 다음 항목 R (증가하지 않는 높이)을 레벨에 패킹합니다. R을 수용 할 수있는 레벨이 없으면 새 레벨이 작성됩니다.

  4. 왼쪽 아래 (BL) 알고리즘
    BL 첫 번째 항목은 너비가 증가하지 않습니다. BL은 포장 된 품목과 겹치지 않고 다음 품목을 바닥에 가깝게 포장 한 다음 왼쪽에 가깝게 포장합니다. BL은 레벨 지향 패킹 알고리즘이 아닙니다.
    시간 복잡도 : O (n ^ 2).
    근사 비율 : BL (I) <= 3 · OPT (I).

  5. 베이커 업다운 (UD) 알고리즘
    UD는 BL과 NFDH의 일반화의 조합을 사용합니다. 스트립 및 아이템의 폭은 스트립이 단위 폭이되도록 정규화된다. UD는 항목을 증가하지 않는 너비로 주문한 다음 너비가 (1/2, 1], (1 / 3,1 / 2], (1 / 4,1 / 3) 인 5 개의 그룹으로 항목을 나눕니다. ], (1 / 5,1 / 4], (0,1 / 5]. 스트립은 또한 5 개의 영역 R1, ···, R5로 나뉘며 기본적으로 (1 / i + 범위의 일부 항목) 1 <= i <= 4의 경우 1, 1 / i]는 영역 Ri에 BL로 패킹됩니다. j = 1, ···, 4 (순서대로) 위에서 아래로 Rj에 항목을 포장합니다. 이런 공간이 없으면 항목은 Ri에 의해 BL에 의해 포장됩니다. (일반화 된) NFDH 알고리즘에 의해 R1, ··· R4의 공간에 압축됩니다.
    근사 비율 : UD (I) <= (5/4) · OPT (I) + (53/8) H. 여기서 H는 품목의 최대 높이입니다. 5/4의 점근 적 경계는 빡빡합니다.

  6. RF (Reverse-Fit) 알고리즘
    RF는 또한 스트립의 너비와 항목을 정규화하여 스트립이 단위 너비가되도록합니다. RF는 먼저 1/2보다 큰 너비의 모든 항목을 쌓습니다. 나머지 품목은 높이가 아닌 높이로 분류되며 높이 H0 이상이 1/2보다 큰 높이로 포장됩니다. 그런 다음 RF는 다음 프로세스를 반복합니다. 대략적으로 말하면 RF는 더 이상 공간이 없을 때까지 높이 H0 라인을 따라 하단에서 왼쪽에서 오른쪽으로 항목을 포장합니다. 그런 다음 전체 너비가 1/2 이상이 될 때까지 항목을 오른쪽에서 왼쪽으로 그리고 위에서 아래로 (역 레벨이라고 함) 포장합니다. 그런 다음 리버스 레벨은 (적어도) 그들 중 하나가 아래 항목에 닿을 때까지 내려갑니다. 드롭 다운이 어떻게 든 반복됩니다.
    근사 비율 : RF (I) <= 2 · OPT (I).

  7. Steinberg의 알고리즘
    논문에서 M으로 표시된 Steinberg의 알고리즘은 모든 항목을 포장하는 데 필요한 높이 H의 상한을 추정하여 입력 항목을 너비 W와 높이 H의 사각형으로 포장 할 수 있음을 증명합니다. 문제를 두 개의 작은 문제로 나누고 재귀 적으로 해결하는 7 가지 절차 (7 가지 조건)를 정의합니다. 다루기 쉬운 문제는 7 가지 조건 중 하나를 만족시키는 것으로 나타났습니다.
    근사 비율 : M (I) <= 2 · OPT (I).

  8. SF (Split-Fit algorithm) SF는 항목을 너비가 1/2보다 큰 L1과 최대 1/2 인 L2의 두 그룹으로 나눕니다. L1의 모든 품목은 먼저 FFDH에 의해 포장됩니다. 그런 다음 너비가 2/3 이상인 모든 항목이 너비가 2/3 이하인 항목보다 아래에 배치됩니다. 너비 1/3의 공간으로 직사각형 R을 만듭니다. 그런 다음 L2의 나머지 항목은 R로 패킹되고 FFDH를 사용하여 L1으로 패킹 된 것보다 위의 공간이 패킹됩니다. R에서 작성된 레벨은 L1의 패킹 위의 레벨보다 낮은 것으로 간주됩니다.
    근사 비율 : SF (I) <= (3/2) · OPT (I) + 2; 3/2의 점근 적 경계는 빡빡합니다.

  9. Sleator의 알고리즘
    Sleater의 알고리즘은 다음 네 단계로 구성됩니다.

    1. 너비가 1/2보다 큰 모든 항목은 스트립 맨 아래에서 서로 위에 포장됩니다. h0가 결과 패킹의 높이라고 가정하고 모든 후속 패킹은 h0 이상에서 발생합니다.

    2. 나머지 품목은 높이가 아닌 순서로 주문됩니다. 높이 h0 라인을 따라 왼쪽에서 오른쪽으로 항목의 레벨이 증가하지 않는 높이 순서로 포장됩니다.

    3. 그런 다음 가운데에 세로 선을 그려 스트립을 두 개의 동일한 절반으로 자릅니다 (이 선은 부분적으로 오른쪽 절반에 포장 된 품목을자를 수 있음). 길이가 절반 인 두 개의 가로 선 세그먼트를 왼쪽 절반 (왼쪽 기준선이라고 함)과 오른쪽 절반 (오른쪽 기준선이라고 함)을 가로 질러 두 선이 항목을 가로 지르지 않도록하십시오.

    4. 왼쪽 또는 오른쪽 기준선을 더 낮은 높이로 선택하고 다음 항목이 너무 넓을 때까지 스트립의 해당 절반에 항목을 포장하십시오.

    새로운 기준선이 형성되고 모든 품목이 포장 될 때까지 하부 기준선에서 단계 (4)가 반복된다.
    시간 복잡도 : O (n · log n).
    Sleator 알고리즘의 근사 비율은 2.5이며 이는 엄격합니다.


포장 문제를 살펴보십시오 . 나는 당신이 '2D 빈 포장'에 속한다고 생각합니다. 솔루션에서 그와 다른 포장 문제에 이르기까지 많은 것을 배울 수 있어야합니다.

직사각형 이미지 데이터를 정사각형 텍스처로 패킹하기도 참조하십시오 .


이 문제에 대한 광범위한 문헌이 있습니다. 욕심 많은 휴리스틱은 컨테이너의 맨 아래와 왼쪽을 향한 첫 번째 사용 가능한 위치에서 가장 큰 영역에서 가장 작은 사각형으로 사각형을 배치하는 것입니다. 중력이 모든 항목을 왼쪽 아래 모서리로 당기는 것을 생각하십시오. 이 구글 "Chazelle 하단 왼쪽 포장"에 대한 설명.

최적의 솔루션을 위해 최첨단 기술은 몇 초 안에 20 개 이상의 직사각형을 포장 할 수 있습니다. Huang은 가장 작은 엔 클로징 경계 상자를 찾는 문제와 사각형 집합이 특정 크기의 경계 상자에 맞는지 여부를 결정하는 문제를 분리 하는 알고리즘가지고 있습니다. 당신은 그의 프로그램에 직사각형 세트를 주었고, 그것들을 포장하는데 필요한 가장 작은 둘러싸는 경계 상자를 알려줍니다.

귀하의 경우 외부 루프는 가능한 가장 작은 경계 상자에서 위로 반복해야합니다 (폭과 높이가 2의 거듭 제곱에 따라 연속적으로 증가 함). 이 경계 상자 각각에 대해 사각형의 패킹을 찾을 수 있는지 테스트하십시오. 첫 번째 "예"답변이 나올 때까지 많은 "아니오"답변을 얻을 수 있으며 이는 최적의 솔루션이 될 것입니다.

특정 크기의 경계 상자에 "예"또는 "아니오"로 응답하는 알고리즘의 내부 루프의 경우 Huang 참조를 찾아 알고리즘을 구현합니다. 그는 기본 알고리즘 위에 많은 최적화를 포함하지만 기본 고기와 감자 만 있으면됩니다. 회전을 처리하려면 검색 중 모든 분기 지점에서 회전이 모두 해결되지 않으면 회전과 역 추적을 모두 시도하십시오.


나는 이것이 NP-hard 문제 라고 확신합니다 . 따라서 최적의 솔루션을 얻으려면 가능한 모든 조합을 시도하는 역 추적 알고리즘을 구현해야합니다.

좋은 소식은 제한된 2D 공간에 2D 직사각형을 포장해야하기 때문에 초기에 많은 가능성을 정리할 수 있으므로 그렇게 나쁘지 않을 수 있습니다.


필요한 것은 https://github.com/nothings/stb/blob/master/stb_rect_pack.h입니다.

견본:

stbrp_context context;

struct stbrp_rect rects[100];

for (int i=0; i< 100; i++)
{
    rects[i].id = i;
    rects[i].w = 100+i;
    rects[i].h = 100+i;
    rects[i].x = 0;
    rects[i].y = 0;
    rects[i].was_packed = 0;
}

int rectsLength = sizeof(rects)/sizeof(rects[0]);

int nodeCount = 4096*2;
struct stbrp_node nodes[nodeCount];


stbrp_init_target(&context, 4096, 4096, nodes, nodeCount);
stbrp_pack_rects(&context, rects, rectsLength);

for (int i=0; i< 100; i++)
{
    printf("rect %i (%hu,%hu) was_packed=%i\n", rects[i].id, rects[i].x, rects[i].y, rects[i].was_packed);
}

일반적인 해결책은 사소하지 않습니다 (수학은 완전히 불가능하다고 말하십시오)
일반적으로 사람들은 가능한 조합을 시도하기 위해 유전자 알고리즘을 사용하지만 가장 큰 모양을 먼저 놓고 다른 장소를 시도하여 합리적으로 잘 할 수 있습니다 다음으로 큰 등.


나는 다음 중 하나를 사용하고 있습니다 :

https://codereview.stackexchange.com/questions/179565/incremental-2d-rectangle-bin-packer?newreg=cce6c6101cf349c58423058762fa12b2

단두대 알고리즘을 구현하고 한 차원을 입력으로 요구하고 다른 차원을 최적화하려고 시도합니다 (코드를 약간 변경하여 최대 값을 설정할 수도 있음). 어쩌면 두 값의 다른 힘을 시도하면 효과가 있습니다.

어떤 식 으로든 최적은 아니지만 작고 휴대 가능하며 (.h 만) C ++ 및 STL 이외의 다른 종속성이 없습니다.

참고 : https://stackoverflow.com/questions/1213394/what-algorithm-can-be-used-for-packing-rectangles-of-different-sizes-into-the-sm

반응형