排列任意矩形以填充空间


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值,例如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

注意:您无需说明如何安排,只需确定是否可以安排。

这是代码高尔夫球,所以最短的答案以字节为单位!自1月14日起,我将接受最短的答案,但请在此之后提交答案,因为我仍然可以放弃投票!:)

打高尔夫球快乐!

〜AL

PS:如果您知道应该对这个问题应用什么标签,请添加它,我完全不知道除代码高尔夫球之外应放置什么标签。

编辑:您的程序应该能够在一台像样的计算机上最多在10秒内处理多达25个矩形(我会很灵活地遵守此规则)。

编辑:我已经将提交接受的截止日期延长到了一年的最后一天,但我怀疑届时我会得到答复...

编辑:我已经将提交接受的截止日期延长了2周,因此如果届时没有更多答案,那么当前的C答案将被接受!:)


我认为每个输入矩形只能使用一次吗?
同或

7
为什么会有最后期限?您可能会说那时您会接受答案,但是挑战应该无限期开放:)
Nathan Merrill

4
矩形可以旋转吗?
xnor

3
好吧,您的问题是可判定性问题:“可以将这些定向的矩形排列成零浪费的另一个矩形”,这是一个NP完全问题(Korf,2003:pdfs.semanticscholar.org/90a5/…)。Korf的算法本质上是蛮力的,并进行了一些优化以更有效地消除没有解决方案的配置。我怀疑这种语言在大多数语言中会少于250个字符。
加布里埃尔·贝纳米

1
简单的方法是确定是否可以重复组合两个相同宽度或高度的矩形,直到剩下1个矩形为止。该算法适用于所有当前的测试用例。但是,它失败了[[1, 2], [2, 1], [1, 1], [1, 2], [2, 1]](可以安排ABB ACD EED)。您可能想要添加这个简单的测试用例。
ETHproductions 2016年

Answers:


5

C,1135 1158 1231 1598字节

嗯,已经超过了规定的期限,但是看到没有答案,这是C语言中的一个(有点长)。

返回值:

  • 失败时0(零)(不适合)
  • 成功的完全拟合矩阵

更新:

原始代码可能会卡在某些矩阵上,所需时间比允许的10s长得多。当前修订版应在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);}

未打高尔夫球:

#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个功能:mainOQFLTT ESTS以查看是否有用于在给定的点的矩形空间。 LFIL 是个矩形到输出缓冲器或交替地通过重写它删除之一。OQ建立左和顶壁,分别与F ˚F顽疾矩形的由迭代搜索的余数。

尽管基本搜索是迭代的,但我们首先通过为主矩形建立允许的宽度和高度组合,然后消除不可能的配置,来消除绝大多数可能的搜索向量。通过在填充中心之前确定底壁和右壁,可以在较大的矩形中获得额外的速度,但是当限制为25个内部矩形时,对于体面的速度并不需要此速度。


不错的工作!它似乎正在工作...但是,您可以指定输出格式吗?看来它在打印东西,如果它可以工作,那么它会崩溃,如果它不能,那么我会允许的,因为无论如何这是唯一的答案。另外,您可以通过打印“ 1”而不是“每个人都适合”来节省很多字节。(因为这是允许的),并且通过不打印它们的排列方式还占用了很多字节。可以很好地打印出来,但是它使用了不必要的字节,目的是节省下来。否则,做得好!我将截止日期延长了半个月,但现在,请投票。:)
HyperNeutrino

谢谢。我进行了更新以指定格式并修复了崩溃(这是无意的)。我离开了矩阵输出(+ 30bytes),因为它很漂亮,而且如果有人发布了高尔夫球语言解决方案,他们将不会只是击败我30 :)
赛斯(Seth)

-367字节...可能是有史以来最大的高尔夫吗?:-)
HyperNeutrino

:-)嗯,有一个hack-y的起点很有帮助。
赛斯

当然可以!我最大的尝试是用Java编辑了337个字符,然后我有了一些非常糟糕的主意(哦,美好的过去,我创建了5000万个变量,只需要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上尝试

怎么运行的

这将以递归方式搜索形状为Young图表的所有部分切片,一次添加一个矩形,并检查最终结果是否为矩形。

要看到可以用这种方式构建矩形的任何平铺:在非空Young图的任何平铺中,令R为平铺中其西南角不接触任何其他矩形的矩形的集合。由于杨氏图的每个凹顶点在R中最多与一个矩形边缘相邻(而不仅仅是与角相邻),并且这些凹顶点的数量比R中的矩形数量少一个,因此必须至少有一个R中的一个矩形,不与这些凹形顶点中的任何一个相邻。删除它会产生另一个杨氏图,因此我们可以通过归纳法进行。


好东西!这是太棒了。做得好!:)
HyperNeutrino
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.