Piet (Mondrian)의 퍼즐


20

자세한 내용은 이 비디오를 보고 A276523 으로 이동하여 관련 시퀀스를 확인하십시오.

몬드리안 퍼즐 (정수 n)은 다음과 같습니다.

일치하지 않는 사각형을 n*n사각형 격자에 맞 춥니 다 . 가장 큰 사각형과 가장 작은 사각형의 가장 작은 차이점은 무엇입니까?

의 경우 6최적의 차이는 M(6)입니다 5. 다음과 같이 설명 할 수 있습니다.

 ___________
| |S|_______|
| | |   L   |
| |_|_______|
| |     |   |
| |_____|___|
|_|_________| (fig. I)

가장 큰 사각형 (L)의 면적은 2 * 4 = 8이고 가장 작은 사각형 (S)의 면적은 1 * 3 = 3입니다. 따라서 차이점은 8 - 3 = 5입니다.

현재로서는 최적의 솔루션을 n > 44찾지 못했습니다 .

당신의 작업은 integer 주어진 주어진 (최적의) 솔루션을 포함하는 몬드리안 그리드를 생성하는 프로그램을 만드는 것 n입니다.

100에서 150까지의 숫자로 시험을 볼 것입니다. 각 시험에 대한 점수는 가장 큰 직사각형과 가장 작은 직사각형의 차이입니다. 총점은 100에서 150까지의 모든 시험에 대한 점수의 합입니다.

다음과 같이 출력을 제시해야합니다.

{number}
{grid}

number점수는 어디에 있습니까 (가장 큰 차이와 가장 작은 차이) grid:

  • 여러 줄로 된 문자열 또는
  • 2 차원 목록.

그리드는 사각형이 시작하고 끝나는 위치를 명확하게 보여줘야합니다.

규칙 :

  • 귀하의 프로그램은 귀하의 답변에 부합해야합니다.
  • 프로그램은 최신 랩톱에서 1 시간 이내에 100에서 150 사이의 숫자를 출력해야합니다.
  • n프로그램이 실행될 때마다 프로그램은 정수에 대해 동일한 솔루션을 생성해야합니다 .
  • Pastebin, Github Gist ...를 사용하여 모든 51 솔루션의 출력에 대한 링크를 제공해야합니다.
  • 솔루션의 사각형 격자에는 두 개 이상의 사각형이 있어야합니다.

1
OEIS A276523 . 나열된 상한은 개선하기가 매우 쉽습니다.
피터 테일러

하아. 나는 일주일 전에 같은 비디오를 보았고, 나의 첫 번째 생각은 그것을 해결하기 위해 프로그램을 만들려고 노력했다. 그래도 완전히 잊어 버렸습니다.
Carcigenicate

4
거기에 넣으려면 Piet 답변이 필요 합니다. 어쩌면 그것에 대한 현상금 ...
NoOneIsHere

답변:


11

피에트, 9625

(드디어 작동합니다!)

사람들은 그것을 요구 했으므로 여기 있습니다. 이것은 매우 순진한 솔루션입니다 (실제로 OEIS 페이지의 느슨한 상한과 동일). 각 사각형을 두 개의 사각형으로 나눕니다.

이 요지는 다음 두 파일 의 세부 사항포함 합니다.

  • 필요한 모든 입력에 대한 프로그램 출력 (npiet v1.3 사용). 나는 stdout 만 캡처 했으므로 ?입력 프롬프트가 출력 점수에 이어 즉시 그리드가 표시됩니다.
  • 프로그램을 계획 할 때 사용한 "의사-조립"소스.

피펫 솔루션, 코덱 크기 10

설명

이 프로그램은 단일 번호를 사용합니다 N 를 입력으로 사용합니다. 숫자가 홀수이면 점수가 숫자입니다. 짝 수면 점수는 두 배입니다.

점수를 출력 한 후 프로그램의 나머지 왼쪽 부분에는 다음과 같은 5 가지 정보가 스택에 채워집니다.

  • 격자 너비 N )
  • 인쇄 할 줄 수
  • 그리드 전체에 인쇄 할 문자 _ 또는 공백)
  • 그리드의 각 가장자리에 인쇄 할 문자 (공백 또는 |)

프로그램의 오른쪽은 각 4 개의 값 세트를 가져 와서 그리드의 해당 부분을 인쇄합니다.


어쨌든 현상금을 얻습니다!
NoOneIsHere 여기

게시하려면 솔루션이 유효해야합니다.
mbomb007

@ mbomb007 좋아, 나는 그것을 몰랐다. 7 일 안에 완료되기를 바랍니다.
NoOneIsHere 여기

6

C 6108

이것은 최소 솔루션의 재귀 적 (실제로 반복적 인) 버전을 사용합니다. 사각형을 면적의 절반보다 약간 큰 두 개의 사각형으로 나누는 대신 N 사각형으로 나눕니다. 따라서 첫 번째 사각형은 1/N전체 영역 보다 약간 큽니다 . 그런 다음 나머지를 취하면 프로그램은 1/(N-1)나머지를 마지막 사각형으로 사용할 때까지 나머지 보다 조금 큰 사각형을 분리합니다 . 사각형은 시계 방향 나선형으로 나머지 부분에서 잘립니다. 먼저 상단에서 오른쪽으로

이것은 넓은 공간을 검색하는 대신 매우 직접적인 방법이므로, 주어진 문제 세트에 대해 각각 74 개의 솔루션을 찾는 데 약 25 초 (라즈베리 파이에서) 소요됩니다.

내 의도는 이러한 결과를 사용하여보다 정교한 접근 방식을 위해 검색 알고리즘에 더 잘 알립니다.

출력은 사각형의 정점에 대한 점수와 (아스키) 도면 및 좌표를 모두 제공합니다. 정점은 해당 사각형의 왼쪽 상단에서 시작하여 시계 방향입니다.

gcc 4.9.2-10을 사용하여 개발되었습니다.

https://github.com/JaySpencerAnderson/mondrian의 결과

암호:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
typedef struct {
    int y, x, height, width;
} rectangle;
#define min(x,y) (((x)<(y))?(x):(y))
#define max(x,y) (((x)>(y))?(x):(y))
#ifndef TRUE
#define TRUE -1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define MAXCOUNT 75

void initstack(rectangle *s, int n){
    int i;
    for(i=0;i<n;i++){
        s[i].y=s[i].x=s[i].height=s[i].width=0;
    }
}
int valid(rectangle *s,int n){
    int i,j;
    for(i=0;i<n-1;i++){
        for(j=i+1;j<n;j++){
            if(min(s[i].height,s[i].width) == min(s[j].height,s[j].width) && max(s[i].height,s[i].width) == max(s[j].height,s[j].width)){

                initstack(s, n);
                return FALSE;
            }
        }
    }
    return TRUE;
}
int horizontal(rectangle s, int y, int x){
    if(s.y == y && x >= s.x && x < s.x+s.width){
        return TRUE;
    }
    else if(s.y+s.height == y && x >= s.x && x < s.x+s.width){
        return TRUE;
    }
    return FALSE;
}
int vertical(rectangle s, int y, int x){
    if(s.x == x && y > s.y && y <= s.y+s.height){
        return TRUE;
    }
    else if(s.x+s.width == x && y > s.y && y <= s.y+s.height){
        return TRUE;
    }
    return FALSE;
}
void graph(rectangle *s, int n, int side){
    unsigned int row,col,i;
    unsigned int line;
    printf("{\n");
/* vertical lines take precedence since "1" cell is 1 char high and 2 char wide */
    for(row=0;row<=side;row++){
        for(col=0;col<=side;col++){
            line=0;
/* Possible values are "  " (0), "__" (1), "| " (2) or "|_" (3). */
            for(i=0;i<n;i++){
                if(horizontal(s[i],row,col)){
                    line|=1;
                }
                if(vertical(s[i],row,col)){
                    line|=2;
                }
            }

            switch(line){
            case 0: printf("  ");   break;
            case 1: printf("__");   break;
            case 2: printf("| ");   break;
            case 3: printf("|_");   break;
            default: printf("##");  break;
            }
        }
        printf("\n");
    }
    printf("}\n");
}
unsigned int score(rectangle *s, int n){
    int i;
    unsigned int smallest,biggest;

    smallest=biggest=s[0].width*s[0].height;

    for(i=0;i<n;i++){
        smallest=min(smallest,s[i].width*s[i].height);
        biggest=max(biggest,s[i].width*s[i].height);
    }
    return biggest-smallest;
}
void report(rectangle *s, int n, int side){
    int i;

    printf("{%d}\n",score(s,n));
    graph(s, n, side);
    printf("{\n");
    for(i=0;i<n;i++){
        printf("[%d,%d] ",s[i].x,s[i].y);
        printf("[%d,%d] ",s[i].x+s[i].width,s[i].y);
        printf("[%d,%d] ",s[i].x+s[i].width,s[i].y+s[i].height);
        printf("[%d,%d]\n",s[i].x,s[i].y+s[i].height);
    }
    printf("\n}\n");
}
void locateandrotate(rectangle *stack, int n){
    unsigned int scratch,i;
    for(i=1;i<n;i++){
        /* Odd rectangles are on their side */
        if(i&1){
            scratch=stack[i].width;
            stack[i].width=stack[i].height;
            stack[i].height=scratch;
        }
        switch(i%4){
        case 0:
            stack[i].x=stack[i-1].x+stack[i-1].width;
            stack[i].y=stack[i-1].y;
            break;
        case 1:
            stack[i].x=stack[i-1].x+stack[i-1].width-stack[i].width;
            stack[i].y=stack[i-1].y+stack[i-1].height;
            break;
        case 2:
            stack[i].x=stack[i-1].x-stack[i].width;
            stack[i].y=stack[i-1].y+stack[i-1].height-stack[i].height;
            break;
        case 3:
            stack[i].x=stack[i-1].x;
            stack[i].y=stack[i-1].y-stack[i].height;
            break;
        default:
            printf("Woops!\n");
        }
    }
}
/* These are the height and width of the remaining area to be filled. */
void door(rectangle *stack, unsigned int height, unsigned int width, unsigned int n, unsigned int totaln){
    unsigned int thisheight, thiswidth;
    int i;

    for(i=0;i<totaln;i++){
/* Not yet used */
        if(stack[i].width == 0){
            stack[i].width=width;
            if(i+1 == totaln){
                stack[i].height=height;
            }
            else {
/* Sometimes yields congruent rectangles, as with 16x16, 8 rectangles */
                if(totaln&1 || height%n){
                    int j;
                    stack[i].height=height-(((n-1)*height)/n);
                }
                else {
                    stack[i].height=height-((((n-1)*height)-1)/n);
                }
                /* Exchange height and width to rotate */
                door(stack,width,height-stack[i].height,n-1,totaln);
            }
            return;
        }
    }
}
void usage(char *argv[],int side){
    printf("Usage: %s -s <side-length>\n",argv[0]);
    printf("Purpose: Calculate N non-congruent rectangles arranged to exactly fill a square with the specified side length.\n");
    printf("Defaults: %s -s %d\n",argv[0],side);
    exit(0);

}
int main(int argc, char *argv[]){
    int side=16;
    int n,bestscore,bestn=2;
    int status;

    while((status=getopt(argc,argv,"s:h")) >= 0){
        switch(status){
        case 's':
            sscanf(optarg,"%d",&side);
            break;
        case 'h':
        default:
            usage(argv,side);
        }
    }

    bestscore=side+side;

    rectangle stack[MAXCOUNT],best[MAXCOUNT];
    for(n=2;n<=MAXCOUNT;n++){
        initstack(stack,MAXCOUNT);
        door(stack, side, side, n, n);
        locateandrotate(stack, n);
        if(valid(stack,n)){
            if(score(stack,n) < bestscore){
                bestn=n;
                initstack(best,MAXCOUNT);
                door(best, side, side, n, n);
                locateandrotate(best, n);

                bestscore=score(best,n);
            }
        }
    }
    report(best,bestn,side);
}

1
음 ... 헤더에 최종 점수를 줄 수 있습니까? 감사. 그러나 좋은 해결책은 해결책을 기대하지 않았습니다 ( '며칠 동안 아무도 대답하지 않았기 때문에).
clismique

1

C-2982

이 프로그램은 광범위한 결과 집합을 통해 검색을 구현합니다. 이 검색을 실용적으로 만드는 데있어 중요한 부분은 초기에 실패하거나 나쁜 길을 밟지 않는 것이 었습니다.

솔루션으로 고려할 사각형 세트가 생성됩니다. 생성 된 사각형 세트는 유용하지 않은 치수를 가진 사각형을 피합니다. 예를 들어, 프로그램이 8 개의 사각형으로 나눈 128x128 정사각형에 대한 솔루션을 찾으려고하면 128x16의 사각형이 생성됩니다. 120의 끝에서 간격을 채울 너비가 8 인 직사각형을 생성 할 가능성이 없기 때문에 120x17이라는 것을 생성하지 않습니다.

사각형을 배치하기위한 초기 전략은 사각형의 둘레 안쪽에 사각형을 배치하는 것입니다 (빌더 기능). 이런 식으로 알고리즘은 각 시퀀스에서 선택한 시퀀스에 문제가 있는지 여부에 대해 매우 빠른 피드백을받습니다. 직사각형을 배치하는 동안 논리는 공간에 틈이 생겨 직사각형에 비해 너무 좁은 지 계속 지켜보고 있습니다. 주변이 성공적으로 채워지면 남은 사각형으로 남은 공간을 일치 시키려고 전략이 변경됩니다 (일치 기능).

흥미로운 또 다른 사항은 사각형 스택에 대한 롤백으로 트랜잭션을 구현한다는 것입니다.

이 프로그램은 가장 적합한 것을 찾지 않습니다. 예산 (64)이 주어지고 첫 번째 솔루션을 찾으면 종료됩니다. 솔루션을 찾지 못하면 예산을 늘리고 (16) 다시 시도하십시오. 필요한 시간 (I7 프로세서가 장착 된 Dell 랩탑의 경우)은 1 분에서 48 분까지 150 분 동안 1 분에서 48 분 사이였습니다 (1 분에 149 분은 2 분 미만 소요). 모든 51 솔루션은 11 직사각형을 사용했습니다. 51 솔루션의 점수 범위는 41에서 78까지였습니다. 11 개의 사각형을 사용한 이유는 적은 사각형보다 점수가 낮았고 12 개의 사각형이 할당 된 시간보다 훨씬 많은 시간이 걸리는 것 같습니다.

솔루션과 코드는 https://github.com/JaySpencerAnderson/mondrian에 있습니다. . 두 my4 * 파일입니다.

BTW, 이것을 "my4"로 컴파일하고 "./my4 -h"와 같이 실행하면 사용법이 제공됩니다. 실제로 작동하지 않게하려면 "./my4 -l 50 -n 8"과 같은 것을 시도하십시오. "#if 0"을 "#if 1"로 변경하면 화면에 남은 공간이 렌더링됩니다. 사각형을 렌더링하기 위해 이것을 변경하려면 코드가 "graph (space, side)"를 실행하는 지점을 찾아서 대신 "graph (callstack, side)"로 변경하십시오. 또한 너비가 약 50 인 사각형에 대한 솔루션을 가지고 놀고 싶다면 초기 예산을 64에서 32로 변경하는 것이 좋습니다. 작은 사각형에 대한 솔루션은 적은 예산으로 더 나은 점수를 얻습니다.

아래 프로그램은 작동합니다. github에서 전체 코드 (사용법, 주석 등)를 확인하십시오.

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
typedef struct {
    int y, x, height, width, created, deleted;
} rectangle;
#define NOTYET -1
#define TOPEDGE 1
#define RIGHTEDGE 2
#define BOTTOMEDGE 4
#define LEFTEDGE 8
#define CENTER 16
#define nextEdge(e) (e<<=1)
#define min(x,y) (((x)<(y))?(x):(y))
#define max(x,y) (((x)>(y))?(x):(y))
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define MAXFACTORS 1000
#define EOL printf("\n")
#define isCurrent(r) (r.created != NOTYET && r.deleted == NOTYET)
#define deleteTxn(r,t) (r.deleted=t)
int area(rectangle r){
    return r.width*r.height;
}
void pop(rectangle *s){
    unsigned int k=0;
    while(s[k].width){
        k++;
    }
    s[k-1].width=s[k-1].height=0;
}
void rpush(rectangle *s, rectangle x){
    unsigned int k=0;
    while(s[k].width){
        k++;
    }
    x.deleted=NOTYET;
    s[k++]=x;
    s[k].width=s[k].height=0;

    return;
}
void dumprectangle(rectangle r){
    printf("%dX%d@[%d,%d] (%d,%d)\t",r.width, r.height, r.x, r.y, r.created, r.deleted);
}
void dumpstack(rectangle *s){
    unsigned int k=0;
    while(s[k].width){
        dumprectangle(s[k]);
        k++;
    }
}
rectangle initrectangle(int width, int height){
    rectangle r;
    r.x=r.y=0;
    r.width=width;
    r.height=height;
    r.created=0;
    r.deleted=NOTYET;
    return r;
}
void initstack(rectangle *s, int n){
    int i;
    for(i=0;i<n;i++){
        s[i].y=s[i].x=s[i].height=s[i].width=0;
    }
}
int bitcount(int x){
    int count=0;
    while(x){
        if(x&1){
            count++;
        }
        x>>=1;
    }
    return count;
}
int congruent(rectangle a, rectangle b){
    return min(a.height,a.width) == min(b.height,b.width) && max(a.height,a.width) == max(b.height,b.width);
}
void report(rectangle *s, int side){
    int i;
    unsigned int smallest,biggest,area=0;

    smallest=side*side;
    biggest=0;

    for(i=0;s[i].width;i++){
        if(isCurrent(s[i])){
            smallest=min(smallest,s[i].width*s[i].height);
            biggest=max(biggest,s[i].width*s[i].height);
        }
    }
    printf("{%d}\n",biggest-smallest);
    printf("{\nDimensions\tLocation\n");
    for(i=0;s[i].width;i++){
        printf("%dx%d\t\t[%d,%d]\n",
            s[i].width,         s[i].height,
            s[i].x,             s[i].y);
    }
    printf("}\n");
}
unsigned int sumstack(rectangle *s){
    unsigned int sum=0;
    int i;
    for(i=0;s[i].width;i++){
        if(isCurrent(s[i])){
            sum+=s[i].width*s[i].height;
            s++;
        }
    }
    return sum;
}
unsigned int minstack(rectangle *s){
    unsigned int area=400000;
    int i;

    for(i=0;s[i].width;i++){
        if(isCurrent(s[i])){
            area=min(area,s[i].width*s[i].height);
        }
    }
    return area;
}
void rollback(rectangle *r, int txn){
    int i;

    if(txn != NOTYET){
        for(i=0;r[i].width;i++){
            if(r[i].created == txn){
                r[i].created=r[i].deleted=NOTYET;
                r[i].x=r[i].width=r[i].y=r[i].height=0;
            }
            else if(r[i].deleted == txn){
                r[i].deleted=NOTYET;
            }
        }
    }
}
int overlap(rectangle a, rectangle b){
    if((a.x < b.x+b.width && a.x+a.width > b.x) && (b.y < a.y+a.height && b.y+b.height > a.y)){
        return TRUE;
    }
    return FALSE;
}
int stackoverlap(rectangle *callstack, rectangle next){
    int i,j;
    for(i=0;callstack[i].width;i++){
        if(overlap(callstack[i], next)){
            return TRUE;
        }
    }
    return FALSE;
}
rectangle rotate(rectangle a){
    int x=a.width;
    a.width=a.height;
    a.height=x;
    return a;
}
int buildedge(rectangle *stack, rectangle *callstack,int side, rectangle *space){
    int i,j,edge,goal,nextgoal,x,y,d,mindim,minarea,result=FALSE,spacetxn,stacktxn;
    mindim=side;
    minarea=side*side;
    for(i=0;stack[i].width;i++){
        mindim=min(mindim,min(stack[i].width,stack[i].height));
        minarea=min(minarea,area(stack[i]));
    }
    x=y=0;
    edge=TOPEDGE;
    i=0;
    while(edge == TOPEDGE && callstack[i].width != 0){
        if(callstack[i].x == x && callstack[i].y == y){
            x+=callstack[i].width;
            if(x == side){
                nextEdge(edge);
                y=0;
            }
            i=0;
        }
        else {
            i++;
        }
    }
    while(edge == RIGHTEDGE && callstack[i].width != 0){
        if(callstack[i].x+callstack[i].width == x && callstack[i].y == y){
            y+=callstack[i].height;
            if(y == side){
                nextEdge(edge);
                x=side;
            }
            i=0;
        }
        else {
            i++;
        }
    }
    while(edge == BOTTOMEDGE && callstack[i].width != 0){
        if(callstack[i].x+callstack[i].width == x && callstack[i].y+callstack[i].height == y){
            x-=callstack[i].width;
            if(x == 0){
                nextEdge(edge);
                y=side;
            }
            i=0;
        }
        else {
            i++;
        }
    }
    while(edge == LEFTEDGE && callstack[i].width != 0){
        if(callstack[i].x == x && callstack[i].y+callstack[i].height == y){
            y-=callstack[i].height;
            if(y == 0){
                nextEdge(edge);
            }
            i=0;
        }
        else {
            i++;
        }
    }
    if(edge == CENTER){
        /* rectangles are placed all along the perimeter of the square.
         * Now match will use a different strategy to match the remaining space
         * with what remains in stack */
        if(match(stack,callstack,space)){
            report(callstack,side);
            return TRUE;
        }
        return FALSE;
    }
    switch(edge){
    case TOPEDGE:
        goal=side-x;
        break;
    case RIGHTEDGE:
        goal=side-y;
        break;
    case BOTTOMEDGE:
        goal=x;
        break;
    case LEFTEDGE:
        /* Still a good assumption that callstack[0] is at 0,0 */
        goal=y-callstack[0].height;
        break;
    default:
        fprintf(stderr,"Error: buildedge has unexpected edge (b): %d\n",edge);
        exit(0);
    }
    nextgoal=goal-mindim;
    for(i=0;stack[i].width;i++){
        if(isCurrent(stack[i])){
            for(d=0;d<2;d++){
                switch(edge){
                case TOPEDGE:
                    if(stack[i].width == goal || stack[i].width <= nextgoal){
                        stack[i].x=x;
                        stack[i].y=y;
                        if(!stackoverlap(callstack, stack[i])){
                            spacetxn=nexttransaction(space);
                            stacktxn=nexttransaction(stack);
                            deleteTxn(stack[i],stacktxn);
                            removerectangle(space, stack[i], spacetxn);
                            if(narrow(space) >= mindim && smallest(space) >= minarea){
                                rpush(callstack, stack[i]);
                                if(buildedge(stack, callstack, side, space)){
                                    return TRUE;
                                }
                                pop(callstack);
                            }
                            rollback(space, spacetxn);
                            rollback(stack, stacktxn);
                            stack[i].x=stack[i].y=0;
                        }
                    }
                    break;
                case RIGHTEDGE:
                    if(stack[i].height == goal || stack[i].height <= nextgoal){
                        stack[i].x=x-stack[i].width;
                        stack[i].y=y;
                        if(!stackoverlap(callstack, stack[i])){
                            spacetxn=nexttransaction(space);
                            stacktxn=nexttransaction(stack);
                            deleteTxn(stack[i],stacktxn);
                            removerectangle(space, stack[i], spacetxn);
                            if(narrow(space) >= mindim && smallest(space) >= minarea){
                                rpush(callstack, stack[i]);
                                if(buildedge(stack, callstack, side, space)){
                                    return TRUE;
                                }
                                pop(callstack);
                            }
                            rollback(space, spacetxn);
                            rollback(stack, stacktxn);
                            stack[i].x=stack[i].y=0;
                        }
                    }
                    break;
                case BOTTOMEDGE:
                    if(stack[i].width == goal || stack[i].width <= nextgoal){
                        stack[i].x=x-stack[i].width;
                        stack[i].y=y-stack[i].height;
                        if(!stackoverlap(callstack, stack[i])){
                            spacetxn=nexttransaction(space);
                            stacktxn=nexttransaction(stack);
                            deleteTxn(stack[i],stacktxn);
                            removerectangle(space, stack[i], spacetxn);
                            if(narrow(space) >= mindim && smallest(space) >= minarea){
                                rpush(callstack, stack[i]);
                                if(buildedge(stack, callstack, side, space)){
                                    return TRUE;
                                }
                                pop(callstack);
                            }
                            rollback(space, spacetxn);
                            rollback(stack, stacktxn);
                            stack[i].x=stack[i].y=0;
                        }
                    }
                    break;
                case LEFTEDGE:
                    if(stack[i].height == goal || stack[i].height <= nextgoal){
                        stack[i].x=x;
                        stack[i].y=y-stack[i].height;
                        if(!stackoverlap(callstack, stack[i])){
                            spacetxn=nexttransaction(space);
                            stacktxn=nexttransaction(stack);
                            deleteTxn(stack[i],stacktxn);
                            removerectangle(space, stack[i], spacetxn);
                            if(narrow(space) >= mindim && smallest(space) >= minarea){
                                rpush(callstack, stack[i]);
                                if(buildedge(stack, callstack, side, space)){
                                    return TRUE;
                                }
                                pop(callstack);
                            }
                            rollback(space, spacetxn);
                            rollback(stack, stacktxn);
                            stack[i].x=stack[i].y=0;
                        }
                    }
                    break;
                default:
                    fprintf(stderr,"Error: buildedge has unexpected edge (c): %d\n",edge);
                    exit(0);
                }
                if(callstack[0].width != 0 && stack[i].width != stack[i].height){
                    stack[i]=rotate(stack[i]);
                }
                else {
                    break;
                }
            }
        }
    }
    return FALSE;
}
int populatestack(rectangle *stack, int score, int side, int rectangles){
    int offset,negative,area,mindim;
    rectangle local;

    int avg_area=(side*side)/rectangles;

    if(avg_area < 4){
        /* It's getting too small - really */
        return FALSE;
    }
    local.x=0;
    local.y=0;
    local.created=0;
    local.deleted=NOTYET;

    initstack(stack,MAXFACTORS);
    for(offset=1;offset<=score;offset++){
        negative=offset&1;
        area=avg_area + (negative?(0-(offset>>1)):(offset>>1));
        mindim=area/side;

        if(side*(area/side) == area){
            local.width=side;
            local.height=area/side;
            rpush(stack,local);
        }

        if(area > 0){
            for(local.width=side-mindim;local.width>=area/local.width;local.width--){
                if(local.width*(area/local.width) == area){
                    local.height=area/local.width;
                    rpush(stack,local);
                }
            }
        }
    }
    return TRUE;
}
int solve(int side,int rectangles,int score){
    rectangle stack[MAXFACTORS],callstack[MAXFACTORS];
    rectangle space[MAXFACTORS];
    rectangle universe;

    if(!populatestack(stack, score, side, rectangles)){
        return FALSE;
    }
    if(sumstack(stack) >= side*side){
        initstack(callstack,MAXFACTORS);
        initstack(space,MAXFACTORS);

        /* Initialize space (not occupied by a rectangle) to be side by side
         * where side is the height/width of the square into which the rectangles fit. */
        universe.width=universe.height=side;
        universe.x=universe.y=0;
        universe.created=0;
        universe.deleted=NOTYET;
        rpush(space, universe);

        if(buildedge(stack,callstack,side,space)){
            return TRUE;
        }
    }
    return FALSE;
}
int containsPoint(rectangle a, int x, int y){
    return a.x <= x && a.y <= y && a.x+a.width > x && a.y+a.height > y;
}
int containsRectangle(rectangle a, rectangle b){
    return containsPoint(a, b.x, b.y) && containsPoint(a, b.x+b.width-1, b.y) && containsPoint(a, b.x, b.y+b.height-1) && containsPoint(a, b.x+b.width-1, b.y+b.height-1);
}
int areEqual(rectangle a, rectangle b){
    return a.x == b.x && a.y == b.y && a.width == b.width && a.height == b.height;
}
int nexttransaction(rectangle *r){
    int i,n=NOTYET;

    for(i=0;r[i].width;i++){
        n=max(n,max(r[i].created,r[i].deleted));
    }
    return n+1;
}
void splitrectanglevertically(rectangle *space, int i, int x, int txn){
    rectangle left, right;
    left=right=space[i];
    right.x=x;
    left.width=right.x-left.x;
    right.width-=left.width;
    left.created=right.created=space[i].deleted=txn;
    rpush(space,left);
    rpush(space,right);
}
void splitrectanglehorizontally(rectangle *space, int i, int y, int txn){
    rectangle top, bottom;
    top=bottom=space[i];
    bottom.y=y;
    top.height=bottom.y-top.y;
    bottom.height-=top.height;
    top.created=bottom.created=space[i].deleted=txn;
    rpush(space,top);
    rpush(space,bottom);
}
int smallest(rectangle *space){
    int i,j,smallest;
    rectangle current;
    smallest=0;
    for(i=0;space[i].width;i++){
        if(isCurrent(space[i])){
            current=space[i];
            for(j=0;space[j].width;j++){
                if(isCurrent(space[j]) && i != j){
                    if(current.x+current.width == space[j].x
                    && space[j].y <= current.y && space[j].y+space[j].height >= current.y+current.height){
                        current.width+=space[j].width;
                    }
                    else if(space[j].x+space[j].width == current.x
                    && space[j].y <= current.y && space[j].y+space[j].height >= current.y+current.height){
                        current.x=space[j].x;
                        current.width+=space[j].width;
                    }
                    else if(current.y+current.height == space[j].y
                    && space[j].x <= current.x && space[j].x+space[j].width >= current.x+current.width){
                        current.height+=space[j].height;
                    }
                    else if(space[j].y+space[j].height == current.y
                    && space[j].x <= current.x && space[j].x+space[j].width >= current.x+current.width){
                        current.y=space[j].y;
                        current.height+=space[j].height;
                    }
                }
            }
            if(smallest == 0){
                smallest=current.width * current.height;
            }
            else if(smallest > current.width * current.height){
                smallest=current.width * current.height;
            }
        }
    }
    return smallest;
}
int narrow(rectangle *space){
    int i,j;
    rectangle smallest,current;

    smallest.width=0;
    for(i=0;space[i].width;i++){
        current=space[i];
        if(isCurrent(current)){
            for(j=0;space[j].width;j++){
                if(isCurrent(space[j]) && i != j){
                    if(current.width <= current.height
                    && current.x+current.width == space[j].x
                    && space[j].y <= current.y && space[j].y+space[j].height >= current.y+current.height){
                        current.width+=space[j].width;
                    }
                    else if(current.width <= current.height
                    && space[j].x+space[j].width == current.x
                    && space[j].y <= current.y && space[j].y+space[j].height >= current.y+current.height){
                        current.x=space[j].x;
                        current.width+=space[j].width;
                    }

                    if(current.width >= current.height
                    && current.y+current.height == space[j].y
                    && space[j].x <= current.x && space[j].x+space[j].width >= current.x+current.width){
                        current.height+=space[j].height;
                    }
                    else if(current.width >= current.height
                    && space[j].y+space[j].height == current.y
                    && space[j].x <= current.x && space[j].x+space[j].width >= current.x+current.width){
                        current.y=space[j].y;
                        current.height+=space[j].height;
                    }
                }
            }
            if(smallest.width == 0){
                smallest=current;
            }
            else if(min(smallest.width,smallest.height) > min(current.width,current.height)){
                smallest=current;
            }
        }
    }
    return min(smallest.width,smallest.height);
}
int notEmpty(rectangle *space){
    int i,count;

    for(i=0,count=0;space[i].width;i++){
        if(isCurrent(space[i])){
            count++;
        }
    }
    return count;
}
int isAdjacent(rectangle r, rectangle s){
    if(r.y == s.y+s.height && r.x < s.x+s.width && s.x < r.x+r.width){
        return TOPEDGE;
    }
    if(s.x == r.x+r.width && r.y < s.y+s.height && s.y < r.y+r.height){
        return RIGHTEDGE;
    }
    if(s.y == r.y+r.height && r.x < s.x+s.width && s.x < r.x+r.width){
        return BOTTOMEDGE;
    }
    if(r.x == s.x+s.width && r.y < s.y+s.height && s.y < r.y+r.height){
        return LEFTEDGE;
    }
    return NOTYET;
}

int adjacentrectangle(rectangle *space, int k, int k0){
    int i,edge;
    for(i=k0+1;space[i].width;i++){
        if(i != k && isCurrent(space[i])){
            if(isAdjacent(space[k],space[i]) != NOTYET){
                return i;
            }
        }
    }
    return NOTYET;
}
int expanse(rectangle *space, int j, int d){ /* Returns how far space[j] can expand in the d direction */
    int extent,k,giveUp,distance;
    rectangle result=space[j];

    extent=0;
    giveUp=FALSE;
    distance=0;
    if(d == TOPEDGE || d == BOTTOMEDGE){
        while(extent < space[j].width && !giveUp){
            giveUp=TRUE;
            for(k=0;space[k].width;k++){
                if(k != j && isCurrent(space[k]) && isAdjacent(space[j],space[k]) == d){
                    if(space[j].x+extent == space[k].x){
                        extent+=space[k].width;
                        if(distance == 0){
                            distance=expanse(space,k,d);
                        }
                        else {
                            distance=min(distance,expanse(space,k,d));
                        }
                        giveUp=FALSE;
                    }
                    else if(space[j].x+extent > space[k].x && space[j].x+extent < space[k].x+space[k].width){
                        extent=space[k].x+space[k].width-space[j].x;
                        if(distance == 0){
                            distance=expanse(space,k,d);
                        }
                        else {
                            distance=min(distance,expanse(space,k,d));
                        }
                        giveUp=FALSE;
                    }
                }
            }
        }
        if(extent < space[j].width){
            return 0;
        }
        return space[j].height+distance;
    }
    else if(d == LEFTEDGE || d == RIGHTEDGE){
        while(extent < space[j].height && !giveUp){
            giveUp=TRUE;
            for(k=0;space[k].width;k++){
                if(k != j && isCurrent(space[k]) && isAdjacent(space[j],space[k]) == d){
                    if(space[j].y+extent == space[k].y){
                        extent+=space[k].height;
                        if(distance == 0){
                            distance=expanse(space,k,d);
                        }
                        else {
                            distance=min(distance,expanse(space,k,d));
                        }
                        giveUp=FALSE;
                    }
                    else if(space[j].y+extent > space[k].y && space[j].y+extent < space[k].y+space[k].height){
                        extent=space[k].y+space[k].height-space[j].y;
                        if(distance == 0){
                            distance=expanse(space,k,d);
                        }
                        else {
                            distance=min(distance,expanse(space,k,d));
                        }
                        giveUp=FALSE;
                    }
                }
            }
        }
        if(extent < space[j].height){
            return 0;
        }
        return space[j].width+distance;
    }
    return 0;
}
int match(rectangle *stack, rectangle *callstack, rectangle *space){
    int i,j,k,d,goal,mn;
    int height;
    int spacetxn, stacktxn, calltxn;
    int map;
    rectangle r;

    for(i=0,goal=0;space[i].width;i++){
        if(isCurrent(space[i])){
            goal+=space[i].width*space[i].height;
        }
    }
    if(goal == 0){
        return TRUE;
    }
    mn=minstack(stack);
    if(goal < mn){
        /* The goal (space available) is smaller than any rectangle left in the stack */
        return FALSE;
    }
    spacetxn=nexttransaction(space);
    stacktxn=nexttransaction(stack);
    calltxn=nexttransaction(callstack);
    for(j=0;space[j].width;j++){
        for(i=0;stack[i].width;i++){
            if(isCurrent(stack[i]) && isCurrent(space[j])){
                if(congruent(space[j], stack[i]) && adjacentrectangle(space,j,NOTYET) == NOTYET){
                    r=space[j];
                    r.created=calltxn;
                    rpush(callstack, r);
                    deleteTxn(stack[i],stacktxn);
                    deleteTxn(space[j],spacetxn);
                }
            }
        }
    }
    if(!notEmpty(space)){
        return TRUE;
    }
    rectangle e;
    for(j=0;space[j].width;j++){
        if(isCurrent(space[j])){
            e=space[j];
            for(k=0,map=0;space[k].width;k++){
                if(k != j && isCurrent(space[k])){
                    d=isAdjacent(space[j], space[k]);
                    if(d != NOTYET){
                        map|=d;
                    }
                }
            }
            if(bitcount(map) == 1){ /* space[j] has adjacent space on only one side */
                if(map == TOPEDGE || map == BOTTOMEDGE){
                    e.height=expanse(space,j,map);
                }
                else if(map == LEFTEDGE || map == RIGHTEDGE){
                    e.width=expanse(space,j,map);
                }
                for(i=0;stack[i].width;i++){
                    if(isCurrent(stack[i])){
                        if(congruent(e, stack[i])){
                            e.created=calltxn;
                            rpush(callstack, e);
                            deleteTxn(stack[i],stacktxn);
                            if(!removerectangle(space, e, spacetxn)){
                                printf("Logic error in match/expanse.  Terminating\n");
                                exit(0);
                            }
                            if(match(stack,callstack,space)){
                                return TRUE;
                            }
                            else {
                                rollback(stack,stacktxn);
                                rollback(callstack,calltxn);
                                rollback(space,spacetxn);
                                return FALSE;
                            }
                        }
                        else if(congruent(space[j], stack[i])){
                            r=space[j];
                            r.created=calltxn;
                            rpush(callstack, r);
                            deleteTxn(stack[i],stacktxn);
                            if(!removerectangle(space, r, spacetxn)){
                                printf("Logic error in match/expanse.  Terminating\n");
                                exit(0);
                            }
                            if(match(stack,callstack,space)){
                                return TRUE;
                            }
                            else {
                                rollback(stack,stacktxn);
                                rollback(callstack,calltxn);
                                rollback(space,spacetxn);
                                return FALSE;
                            }
                        }
                    }
                }
            }
        }
    }
    if(notEmpty(space)){
        rollback(stack,stacktxn);
        rollback(callstack,calltxn);
        rollback(space,spacetxn);
        return FALSE;
    }
    return TRUE;
}
int removerectangle(rectangle *space, rectangle r, int ntxn){
    int i,status=TRUE;
    for(i=0;space[i].width;i++){
        if(space[i].deleted == NOTYET){
            if(areEqual(space[i], r)){
                space[i].deleted=ntxn;
                return TRUE;
            }
            else if(containsRectangle(space[i], r)){
                if(r.x > space[i].x){
                    splitrectanglevertically(space, i, r.x, ntxn);
                }
                else if(r.y > space[i].y){
                    splitrectanglehorizontally(space, i, r.y, ntxn);
                }
                else if(r.x+r.width < space[i].x+space[i].width){
                    splitrectanglevertically(space, i, r.x+r.width, ntxn);
                }
                else if(r.y+r.height < space[i].y+space[i].height){
                    splitrectanglehorizontally(space, i, r.y+r.height, ntxn);
                }
            }
            else if(overlap(space[i], r)){  /* we have to split both */
                rectangle aux;
                if(r.x < space[i].x){
                    aux=r;
                    aux.width=space[i].x-r.x;
                    r.x+=aux.width;
                    r.width-=aux.width;
                    if(!removerectangle(space,aux,ntxn)){
                        return FALSE;
                    }
                }
                if(r.x+r.width > space[i].x+space[i].width){
                    aux=r;
                    aux.x=space[i].x+space[i].width;
                    aux.width=r.x+r.width-aux.x;
                    r.width-=aux.width;
                    if(!removerectangle(space,aux,ntxn)){
                        return FALSE;
                    }
                }
                if(r.y < space[i].y){
                    aux=r;
                    aux.height=space[i].y-aux.y;
                    r.y+=aux.height;
                    r.height-=aux.height;
                    if(!removerectangle(space,aux,ntxn)){
                        return FALSE;
                    }
                }
                if(r.y+r.height > space[i].y+space[i].height){
                    aux=r;
                    aux.y=space[i].y+space[i].height;
                    aux.height=r.y+r.height-aux.y;
                    r.height-=aux.height;
                    if(!removerectangle(space,aux,ntxn)){
                        return FALSE;
                    }
                }
                if(areEqual(space[i], r)){
                    space[i].deleted=ntxn;
                    return TRUE;
                }
                else {
                    if(!removerectangle(space,r,ntxn)){
                        return FALSE;
                    }
                    return TRUE;
                }
            }
        }
    }
    return TRUE;
}
int main(int argc, char *argv[]){
    int side=15;
    int n=5;
    int budget=0;
    int status;
    while((status=getopt(argc,argv,"l:n:")) >= 0){
        switch(status){
        case 'l':
            sscanf(optarg,"%d",&side);
            break;
        case 'n':
            sscanf(optarg,"%d",&n);
            break;
        }
    }
    budget=64;
    while(solve(side,n,budget) == FALSE){
        budget+=16;
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.