Sắp xếp các hình chữ nhật tùy ý để lấp đầy một khoảng trống


26

Những hình chữ nhật này có thể lấp đầy một không gian hình chữ nhật?

Cho một loạt các hình chữ nhật, bạn được hỏi liệu chúng có thể được sắp xếp để lấp đầy một không gian hình chữ nhật hay không.

Thông số kỹ thuật

Cho một loạt các m x nhình chữ nhật tùy ý ; 0 <= m, n <= 1000, xác định xem có thể sắp xếp chúng sao cho chúng bao phủ chính xác một khu vực hình chữ nhật mà không có bất kỳ lỗ hổng hoặc chồng chéo. Các hình chữ nhật không thể được xoay và mỗi hình chữ nhật chỉ có thể được đặt một lần.

Đầu vào

Đầu vào cho điều này rất linh hoạt, miễn là đầu vào đưa ra một số loại danh sách các kích thước 2 không gian. Ví dụ: cả hai điều sau đây đều hợp lệ:

Tách biệt bởi không gian, trở về

1 2
1 5
4 5
3 6

Danh sách kích thước

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

Đầu ra

Bất kỳ loại giá trị đúng / sai nào như true / false, 0/1, T / F, True / false, v.v. Nếu bạn sẽ sử dụng một phương thức đầu ra không rõ ràng, vui lòng ghi rõ trong câu trả lời của bạn.

Ví dụ

Trường hợp kiểm tra 1

Đầu vào:

1 1
1 5
2 6

Đầu ra: true(hoặc một cái gì đó tương tự)
Cách sắp xếp nó:

XYYYYY
ZZZZZZ
ZZZZZZ

Trường hợp thử nghiệm 2

Đầu vào:

1 1
2 2

Đầu ra: false(hoặc một cái gì đó tương tự)
Giải thích: Rõ ràng là bạn không thể sắp xếp hai hình vuông có kích thước khác nhau và sắp xếp các cạnh của chúng thẳng hàng.

Trường hợp thử nghiệm 3

Đầu vào:

1 1
1 2
1 2
2 1
2 1

Đầu ra: true(hoặc một cái gì đó tương tự) Cách sắp xếp nó:

AAB
DEB
DCC

Như @ETH Productstions đã chỉ ra, đối với tất cả các trường hợp thử nghiệm khác, bạn có thể tiếp tục kết hợp các hình chữ nhật với độ dài cạnh chung cho đến khi bạn chỉ có một hình chữ nhật, vì vậy trường hợp thử nghiệm này chỉ là để phá vỡ bất kỳ mã nào sử dụng ý tưởng này.

Trường hợp thử nghiệm 4

Đầu vào:

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

Đầu ra: true(hoặc một cái gì đó tương tự)
Cách sắp xếp nó:

AAABBBBEE
AAACCDDDD
FFFFFGGGH
FFFFFGGGH
IIIJJKKLH
IIIMMMMMH

Lưu ý : Bạn không cần nêu cách sắp xếp nó, bạn chỉ cần xác định xem có thể sắp xếp được không.

Đây là mã golf, vì vậy câu trả lời ngắn nhất bằng byte sẽ thắng! Tôi sẽ chấp nhận câu trả lời ngắn nhất kể từ ngày 14 tháng 1, nhưng vui lòng gửi câu trả lời muộn hơn vì tôi vẫn có thể từ bỏ! :)

Chúc bạn chơi golf vui vẻ!

~ AL

PS Nếu bạn biết nên áp dụng thẻ nào cho vấn đề này, vui lòng thêm nó, tôi hoàn toàn không biết nên đặt thẻ nào ngoài thẻ golf.

EDIT : Chương trình của bạn sẽ có thể xử lý tối đa 25 hình chữ nhật, trong tối đa 10 giây trên một máy tính đàng hoàng (tôi sẽ khá linh hoạt theo quy tắc này).

EDIT : Tôi đã gia hạn thời hạn chấp nhận gửi đến ngày cuối cùng của năm, nhưng tôi nghi ngờ tôi sẽ nhận được câu trả lời vào lúc đó ...

EDIT : Tôi đã gia hạn thời hạn chấp nhận gửi thêm 2 tuần, vì vậy nếu sau đó không có câu trả lời nào nữa, câu trả lời C hiện tại sẽ được chấp nhận! :)


Tôi lấy nó mỗi hình chữ nhật đầu vào chỉ được sử dụng một lần?
xnor

7
Tại sao có thời hạn? Bạn có thể nói rằng bạn sẽ chấp nhận câu trả lời vào thời điểm đó, nhưng các thách thức sẽ được mở vô thời hạn :)
Nathan Merrill

4
Các hình chữ nhật có thể được xoay?
xnor

3
Chà, vấn đề của bạn là một vấn đề có thể quyết định: "những hình chữ nhật có định hướng này có thể được sắp xếp để tạo thành một hình chữ nhật khác với 0 chất thải không", đó là một vấn đề hoàn chỉnh NP (Korf, 2003: pdfs.semanticscholar.org/90a5/ tựa ). Thuật toán của Korf về cơ bản là một lực lượng vũ phu với một số tối ưu hóa để loại bỏ các cấu hình hiệu quả hơn mà không có giải pháp. Tôi nghi ngờ một golf trong số này sẽ có dưới 250 ký tự trong hầu hết các ngôn ngữ.
Gabriel Benamy

1
Lộ trình dễ dàng sẽ là xác định xem bạn có thể liên tục kết hợp hai hình chữ nhật có cùng chiều rộng hoặc chiều cao cho đến khi bạn còn 1 hình chữ nhật không. Thuật toán này hoạt động cho tất cả các testcase hiện tại; tuy nhiên, nó không thành công [[1, 2], [2, 1], [1, 1], [1, 2], [2, 1]](có thể được sắp xếp ABB ACD EED). Bạn có thể muốn thêm trường hợp thử nghiệm đơn giản này.
Sản phẩm ETH

Câu trả lời:


5

C, 1135 1158 1231 1598 byte

Chà, đã quá thời hạn đã nêu, nhưng xem như chưa có câu trả lời nào, đây là một (hơi dài) trong C.

Trả về:

  • 0 (không) khi thất bại (không phù hợp)
  • Ma trận phù hợp đầy đủ về thành công

Cập nhật:

Mã gốc có thể bị kẹt trên một số ma trận, mất nhiều thời gian hơn 10 giây cho phép. Sửa đổi hiện tại sẽ hoàn thành tất cả các ma trận trong dưới 1 giây. Điều này được thực hiện bằng 1) Sắp xếp các hình chữ nhật đầu vào và 2) bỏ qua các kích thước lặp lại khi khớp.

Chơi gôn

#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);}

Vô song:

#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);
}

Giải thích: Chúng tôi có 6 chức năng: main, O, Q, F, LT. T t ests để xem nếu có không gian cho hình chữ nhật tại một điểm nhất định. Lfil l s một hình chữ nhật vào bộ đệm đầu ra hoặc, thay thế loại bỏ một bằng cách ghi đè lên nó. OQxây dựng các bức tường bên trái và trên cùng, tương ứng và F f phát hiện phần còn lại của hình chữ nhật bằng cách tìm kiếm lặp.

Mặc dù tìm kiếm cơ bản là lặp đi lặp lại, chúng tôi loại bỏ phần lớn các vectơ tìm kiếm có thể, trước tiên bằng cách xây dựng các kết hợp chiều rộng và chiều cao được phép cho hình chữ nhật chính và sau đó loại bỏ các cấu hình không thể. Tốc độ bổ sung có thể đạt được trong các hình chữ nhật lớn hơn bằng cách xác định các bức tường phía dưới và bên phải trước khi lấp đầy trung tâm nhưng không bắt buộc phải có tốc độ tốt khi giới hạn ở 25 hình chữ nhật bên trong.


Công việc tốt! Nó dường như đang hoạt động ... Tuy nhiên, bạn có thể chỉ định định dạng đầu ra của mình không? Có vẻ như đó là công cụ in nếu nó hoạt động và gặp sự cố nếu không, điều này tôi sẽ cho phép vì dù sao đây cũng là câu trả lời duy nhất. Ngoài ra, bạn có thể tiết kiệm khá nhiều byte bằng cách in "1" thay vì "Mọi người đều phù hợp!" (vì điều đó được cho phép) và cũng có một vài byte bằng cách không in cách chúng được sắp xếp. Thật tuyệt khi được in, nhưng nó sử dụng các byte không cần thiết và mục đích là để tiết kiệm cho điều đó. Nếu không, công việc tốt! Tôi sẽ gia hạn thời hạn thêm nửa tháng, nhưng hiện tại, có một upvote. :)
HyperNeutrino

Cảm ơn. Tôi đã cập nhật để xác định định dạng và khắc phục sự cố (đó là vô ý). Tôi rời khỏi đầu ra ma trận (+ 30byte) bởi vì nó tiện lợi và nếu ai đó đăng một giải pháp ngôn ngữ golf, họ sẽ không đánh bại tôi trước 30 :)
Seth

-367 byte ... Có thể là sân golf lớn nhất từ ​​trước đến nay? :-)
HyperNeutrino

:-) Vâng, nó giúp có điểm bắt đầu hack-y.
Seth

Chắc chắn là có! Golf lớn nhất của tôi là 337 ký tự trong Java qua một số chỉnh sửa và tôi đã bắt đầu với một số ý tưởng khá khủng khiếp (ồ, ngày xưa tốt đẹp khi tôi sẽ tạo ra 50 triệu biến và chỉ cần 2 ...). Dù sao, tôi sẽ tiếp tục chờ câu trả lời, nhưng có vẻ như đây có thể là người duy nhất làm việc!
HyperNeutrino

6

Haskell, 226 byte

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

Hãy thử nó trên Ideone

Làm thế nào nó hoạt động

Điều này đệ quy tìm kiếm tất cả các phần nghiêng có hình dạng là sơ đồ Trẻ , thêm một hình chữ nhật tại một thời điểm và kiểm tra xem có bất kỳ kết quả cuối cùng nào là hình chữ nhật không.

Để thấy rằng bất kỳ ốp lát nào của hình chữ nhật đều có thể được xây dựng theo cách này: trong bất kỳ lát nào của sơ đồ Young không trống, hãy đặt R là tập hợp các hình chữ nhật trong lát gạch có góc phía tây nam không chạm vào bất kỳ hình chữ nhật nào khác. Vì mỗi đỉnh lõm của biểu đồ Young là cạnh liền kề (không chỉ là cạnh liền kề) với nhiều nhất một hình chữ nhật trong R và số lượng các đỉnh lõm này ít hơn một hình chữ nhật trong R, nên ít nhất phải có ít nhất một số hình chữ nhật trong R, một hình chữ nhật trong R nằm cạnh không có một trong các đỉnh lõm này. Loại bỏ nó mang lại một sơ đồ Young khác, vì vậy chúng ta có thể tiến hành bằng cảm ứng.


Đẹp quá Cái này thật tuyệt. Làm tốt lắm! :)
HyperNeutrino
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.