Впорядкування довільних прямокутників для заповнення пробілу


26

Чи можуть ці прямокутники заповнити прямокутний простір?

Враховуючи купу прямокутників, вас запитують, чи можна їх розташувати для заповнення прямокутного простору.

Технічні характеристики

Дано купу довільних m x nпрямокутників; 0 <= m, n <= 1000, визначте, чи можна розташувати їх так, щоб вони покривали саме прямокутну область без жодних отворів чи перекриттів. Прямокутники не можна обертати, і кожен прямокутник може бути розміщений лише один раз.

Вхідні дані

Вхід для цього дуже гнучкий, якщо вхід дає певний перелік 2-пробільних розмірів. Наприклад, обидві наведені нижче дії:

Відокремлений пробілом, поверненням

1 2
1 5
4 5
3 6

Список розмірів

[[1, 2], [1, 5], [4, 5], [3, 6]]

Вихідні дані

Будь-які істинні / хибні значення, такі як true / false, 0/1, T / F, True / False тощо. Якщо ви збираєтесь використовувати метод виведення, що не дуже очевидно, вкажіть у своїй відповіді.

Приклади

Тестовий випадок 1

Вхід:

1 1
1 5
2 6

Вихід: true(або щось подібне)
Як це організувати:

XYYYYY
ZZZZZZ
ZZZZZZ

Тестовий випадок 2

Вхід:

1 1
2 2

Вихід: false(або щось подібне)
Пояснення: Стає очевидним, що ви не можете впорядкувати два квадрати різної величини і змусити їх краї вирівнятись.

Тестовий випадок 3

Вхід:

1 1
1 2
1 2
2 1
2 1

Вихід: true(або щось подібне) Як це організувати:

AAB
DEB
DCC

Як зазначав @ETHProductions, для всіх інших тестових випадків ви можете продовжувати комбінувати прямокутники із загальною довжиною ребра, поки у вас не буде лише одного прямокутника, тому цей тестовий випадок - це просто зламати будь-який код, який використовує цю ідею.

Тестовий випадок 4

Вхід:

3 2
4 1
2 1
4 1
2 1
5 2
3 2
1 4
3 2
2 1
2 1
1 1
5 1

Вихід: true(або щось подібне)
Як це організувати:

AAABBBBEE
AAACCDDDD
FFFFFGGGH
FFFFFGGGH
IIIJJKKLH
IIIMMMMMH

Примітка : Вам не потрібно вказувати, як це оформити, потрібно лише визначити, чи не можна це влаштувати.

Це кодовий гольф, тому найкоротша відповідь у байтах виграє! Я прийму найкоротшу відповідь станом на 14 січня, але сміливо надсилайте відповіді пізніше, оскільки я все-таки можу відмовитись! :)

Щасливого гольфу!

~ AL

PS Якщо ви знаєте, який тег слід застосувати до цієї проблеми, будь ласка, додайте його, я абсолютно не маю уявлення, що поставити як тег, окрім коду-гольфу.

EDIT : Ваша програма повинна мати можливість обробляти до 25 прямокутників, принаймні 10 секунд на пристойному комп’ютері (я буду досить гнучким щодо цього правила).

EDIT : Я продовжив термін прийому заявок до останнього дня року, але я сумніваюся, що отримаю відповідь до цього часу ...

EDIT : Я продовжив термін прийняття заявки на 2 тижні, тому якщо більше відповідей до цього часу не надійде, поточна відповідь C буде прийнята! :)


Я вважаю, що кожен вхідний прямокутник буде використаний лише один раз?
xnor

7
Чому існує термін? Можна сказати, що ви приймете відповідь у той час, але виклики повинні бути відкриті нескінченно :)
Натан Меррілл

4
Чи можна обертати прямокутники?
xnor

3
Ну, ваша проблема полягає в проблемі розбірливості: "чи можуть ці орієнтовані прямокутники розташовуватись таким чином, щоб утворювати ще один прямокутник з 0 відходами", що є повною проблемою NP (Korf, 2003: pdfs.semanticscholar.org/90a5/… ). Алгоритм Корфа по суті є грубою силою з деякими оптимізаціями для більш ефективного усунення конфігурацій без рішення. Я сумніваюсь, що гольф цього рівня буде менше 250 символів на більшості мов.
Габріель Бенамі

1
Простим маршрутом було б визначити, чи можна повторно поєднувати два прямокутники однакової ширини чи висоти, поки у вас не залишиться 1 прямокутник. Цей алгоритм працює для всіх поточних тестів; однак це не вдається [[1, 2], [2, 1], [1, 1], [1, 2], [2, 1]](що можна домовитись ABB ACD EED). Ви можете додати цей простий тестовий випадок.
ETHproductions

Відповіді:


5

C, 1135 1158 1231 1598 байт

Що ж, минуло зазначений термін, але бачимо, як відповіді ще немає, ось одна (трохи довга) у С.

Повернення:

  • 0 (нуль) при відмові (не підходить)
  • Повна придатна матриця про успіх

Оновлення:

Оригінальний код може застрягнути на деяких матрицях, зайнявши набагато більше часу, ніж дозволені 10с. Поточна редакція повинна заповнити всі матриці в межах менше 1. Це досягається 1) сортуванням вхідних прямокутників та 2) пропусканням повторних розмірів при установці.

Гольф:

#define R r[i]
#define Z return
#define _(B,D,E) for(int B=E;B<D;B++)
struct{int x,y,u,p;}r[25],*S;int A,M,N,U,V,X,Y;char *P;T(x,y,w,h){_(I,x+w,x)_(J,y+h,y)if(I/U|J/V|P[J*U+I])Z 0;Z 1;}L(x,y,w,h,c){_(I,x+w,x)_(J,y+h,y)P[J*U+I]=c;}F(){int x=0,y;while(++x<A)if(!P[x])break;if(x/A){_(i,V,0)printf("%*.*s\n",U,U,P+i*U);exit(0);}y=x/U;x-=y*U;_(i,N,0)if(!R.u&T(x,y,R.x,R.y))R.u=1,L(x,y,R.x,R.y,'A'+i),F(),R.u=0,L(x,y,R.x,R.y,0);}O(i,y){if(!R.u){if(!T(0,y,R.x,R.y))Z;R.u=1;R.p=0;L(0,y,R.x,R.y,'A'+i);y+=R.y;}if(y-V||F())_(j,N,0)if(j-i&!r[j].u){O(j,y);while(r[j].x-r[j+1].x|r[j].y-r[j+1].y)j++;}R.u=0;L(R.p,(y-=R.y),R.x,R.y,0);}Q(i,x){if(!R.u){if(R.x>U-x)Z;R.u=1;R.p=x;L(x,0,R.x,R.y,'A'+i);x+=R.x;}if(x-U||O(i,1))_(j,N,0)if(j-i&!r[j].u)Q(j,x);L(x-=R.x,0,R.x,R.y,0);R.u=0;}C(int*a,int*b){Z*a-*b?*a-*b:a[1]-b[1];}main(){_(i,25,0)if(++N&scanf("%d%d\n",&R.x,&R.y)-2)break;_(i,N,0){A+=R.x*R.y;if(R.x>X)X=R.x;if(R.y>Y)Y=R.y;}_(i,A+1,1)if(!(A%i)){if(i<Y|A/i<X)continue;M++;S=realloc(S,M*16);S[M-1].y=i;S[M-1].x=A/i;}qsort(S,M,16,C);P=calloc(A+1,1);_(j,M,0){U=S[j].x;V=S[j].y;_(i,N,0)R.u=1,L(0,0,R.x,R.y,'A'+i),Q(i,R.x),R.u=0;}printf("0\n");exit(1);}

UnGolfed:

#define R r[i]
#define Z return
#define _(B,D,E) for(int B=E;B<D;B++)
struct {
    int x,y,u,p;
} r[25],*S;
int A,M,N,U,V,X,Y;
char *P;

test_space(x,y,w,h) {
    _(I,x+w,x)
        _(J,y+h,y)
            if (    I >= U |
                    J >= V |
                    P[J*U+I]) Z 0;
    Z 1;
}
place_rect(x,y,w,h,c){
    _(I,x+w,x)
        _(J,y+h,y)P[J*U+I] = c;
}

fill_rest() {
    int x=0,y;
    while(++x<A) if (!P[x])break;
    if (x>=A) {
        _(i,V,0) printf("%*.*s\n", U,U, P+i*U);
        exit(0);
    }
    y = x / U; x -= y*U;

    _(i,N,0)
        if (!R.u & test_space(x, y, R.x, R.y))
                R.u = 1,
                place_rect(x, y, R.x, R.y, 'A'+i),
                fill_rest(),
                R.u = 0,
                place_rect(x, y, R.x, R.y, 0);

}

fill_y(i,y) {
    if (!R.u) {
        if (!test_space(0, y, R.x, R.y)) Z;
        R.u = 1;
        R.p = 0;
        place_rect(0, y, R.x, R.y, 'A'+i);
        y += R.y;
    }
    if (y == V) fill_rest();
    else _(j,N,0)
        if (j!=i && !r[j].u){ fill_y(j, y);
        while (r[j].x^r[j+1].x||r[j].y^r[j+1].y)j++;
        }
    R.u = 0;
    place_rect(R.p, (y -= R.y), R.x, R.y, 0);
}

fill_x(i,x) {
    if (!R.u) {
        if (R.x > U - x) Z;
        R.u = 1;
        R.p = x;
        place_rect(x, 0, R.x, R.y, 'A'+i);
        x += R.x;
    }
    if (x == U) fill_y(i, 1);
    else
        _(j,N,0)
            if (j!=i && !r[j].u) fill_x(j, x);
    place_rect((x -= R.x), 0, R.x, R.y, 0);
    R.u = 0;
}
C(int*a,int*b) {
    Z *a^*b?*a-*b:a[1]-b[1];
}


main() {
    _(i,25,0)
        if (++N&&scanf("%d %d\n", &R.x, &R.y)!=2) break;
    _(i,N,0){
        A+=R.x*R.y;
        if(R.x>X)X=R.x;
        if(R.y>Y)Y=R.y;
    }
    _(i,A+1,1)
        if (!(A%i)) {
            if (i < Y | A/i < X) continue;
            M++;
            S = realloc(S,M*16);
            S[M-1].y=i;
            S[M-1].x=A/i;
        }
    qsort(S, M, 16,C);
    P = calloc(A + 1,1);
    _(j,M,0){
        U = S[j].x; V = S[j].y;
        _(i,N,0)
            R.u = 1,
            place_rect(0, 0, R.x, R.y, 'A'+i),
            fill_x(i, R.x),
            R.u = 0;
    }
    printf("0\n");
    exit(1);
}

Пояснення: У нас є 6 функцій: main, O, Q, F, Lі T. T t оцінює, чи є в даному місці місце для прямокутника. Lфіл л а м прямокутник в вихідний буфер або, альтернативно видаляє один шляхом перезапису його. Oі Qстворити ліві і верхні стінки, відповідно , і F ті бід решту прямокутника шляхом ітеративного пошуку.

Хоча базовий пошук є ітераційним, ми усуваємо переважну більшість можливих векторів пошуку, спочатку створюючи дозволені комбінації ширини та висоти для головного прямокутника, а потім усуваючи неможливі конфігурації. Додаткова швидкість може бути досягнута у більших прямокутниках шляхом визначення нижньої та правої стінок до заповнення центра, але це не потрібно для гідної швидкості при обмеженні 25 внутрішніх прямокутників.


Хороша робота! Схоже, це працює ... Однак ви могли б вказати свій вихідний формат? Здається, що вона друкує речі, якщо вона працює, і вона руйнується, якщо її немає, що я дозволю, оскільки це єдиний варіант відповіді. Крім того, ви можете зберегти досить багато байтів, надрукувавши "1" замість "Усі підходять!" (тому що це дозволено), а також досить багато байт, не друкуючи те, як вони розташовані. Приємно, щоб це було надруковано, але він використовує зайві байти, і мета - заощадити на цьому. Інакше хороша робота! Я продовжую термін на півмісяця, але наразі маю підсумки. :)
HyperNeutrino

Спасибі. Я оновив, щоб вказати формат і виправив збій (це було ненавмисно). Я залишив матричний вихід (+ 30 байт), тому що він чудовий, і якщо хтось інший опублікує рішення мови для гольфу, він не просто биє мене до 30 :)
Сет

-367 байт ... Можливо, найбільший гольф коли-небудь? :-)
HyperNeutrino

:-) Ну, це допомагає мати вихідну точку.
Сет

Звичайно, так! Найбільшим моїм гольфом було 337 символів на Java протягом кількох редагувань, і я почав з дуже жахливих ідей (о, старі добрі часи, коли я створив би 50 мільйонів змінних і мені потрібно лише 2 ...). У будь-якому разі я буду чекати відповіді, але, схоже, це може бути єдиним робочим!
HyperNeutrino

6

Haskell, 226 байт

((y,z):l)&(w,x)|x*y<1=(w+y,x+z):l
(q:l)&p=p:q:l
(p@(u,v):r@(y,z):l)%q@(w,x)=[((y-w,z):l)&q&(u,v-x)|w<=y,x<=v]++[p:m|m<-(r:l)%q]
_%_=[]
g m(p:n)l=any(g[]$m++n)(l%p)||g(p:m)n l
g[]_[_,_,_]=0<1
g _[]_=0<0
($[(0,9^9),(9^9,0)]).g[]

Спробуйте це на Ideone

Як це працює

Цей рекурсивно шукає всі часткові обшивки, формою яких є діаграма Юнга , додаючи по одному прямокутнику за один раз, і перевіряє, чи є будь-який з кінцевих результатів прямокутники.

Щоб побачити, що будь-яка плитка прямокутника може бути побудована таким чином: у будь-якій плитці непустої діаграми Янг нехай R - це набір прямокутників у плитці, південно-західний кут якого не торкається жодного іншого прямокутника. Оскільки кожна увігнута вершина діаграми Янга є сусідньою по краю (а не просто кутовою), щонайменше, до одного прямокутника в R, а кількість цих увігнутих вершин на один менше, ніж кількість прямокутників у R, повинно бути принаймні один прямокутник у R, який примикає до жодної із цих увігнутих вершин. Видалення його дає ще одну діаграму Янга, тож ми можемо продовжувати індукцію.


Хороший! Це фантастично. Хороша робота! :)
HyperNeutrino
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.