四个长宽已知的长方形能否拼成大长方形

 

简化问题 :

四个长方形长宽都已知, 四个面积 S1, S2, S3, S4 已知, 总面积 S = S1 + S2 + S3 + S4 已知

于是枚举长边为length, 宽为width = S / length, 问题转化为, 这四个长方形能否塞进 length * width 的长方形中?

规定小长方形的 l > w, 大长方形的 length > width

 

1. 如果问一个长宽已知的长方形, 问能否正好(不留空)放入length * width的长方形中, 只要长边 == length, 短边 == width 即可

2. 如果问两个长宽已知的长方形, 如果能放入, 那么必然有一个长方形的 长 / 宽 正好和大长方形的一边相等, 剩下一个长方形和剩余部分(也是长方形), 转化为问题1

3. 如果问三个长宽已知的长方形, 如果能放入, 那么必然有一个长方形 长 / 宽 正好和大长方形的一边相等, 剩下二个长方形和剩余部分转化为问题2

4. 可以看出这已经转化为一个递归问题了, 如果给4个? 我们希望先放一个长方形之后转化为问题3

  枚举长 length, 此时宽已知, 为 S / length

    先放入长边最长的长方形, 用来和大长方形的匹配, 此时会出现3种情况  

  一. w > width 不可行

    二.  l == length 或 l == width 或 w == width, 大长方形剩下一块和三个小长方形匹配, 转化为上述问题

           

  三.  l < length 且 w < width, 留下一个不规则的图形, 对这个图形进行分解, 分为3块, S1, S2, S3

    

   显然(弱渣不会证明), 剩下的S1 或 S2, 必然能和3个长方形其中之一匹配, 枚举并成功匹配后, 转化为问题2

 

于是放4个的情况就解决了...

 

这个问题的来路让我很惭愧... 贴出代码, 欢迎指正

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

typedef struct {
    int l, w;
} Rec;

Rec r[5];
bool vis[5];

bool Check(int length, int width, int num)
{
    if(length < width) swap(length, width);
    if(num == 1) {
        for(int i = 1; i < 4; i++) {
            if(vis[i]) continue;
            if(r[i].l == length && r[i].w == width) return true;
        }
    }
    else if(num == 2) {
        for(int i = 1; i < 4; i++) {
            if(vis[i]) continue;
            if(r[i].l == length) {
                vis[i] = 1;
                if(Check(length, width - r[i].w, 1)) return 1;
                else return 0;
            }
            else if(r[i].l == width) {
                vis[i] = 1;
                if(Check(length - r[i].w, width, 1)) return 1;
                else return 0;
            }
            else if(r[i].w == width) {
                vis[i] = 1;
                if(Check(length - r[i].l, width, 1)) return 1;
                else return 0;
            }
        }
    }
    else if(num == 3) {
        for(int i = 1; i < 4; i++) {
            if(vis[i]) continue;
            if(r[i].l == length) {
                vis[i] = 1;
                if(Check(length, width - r[i].w, 2)) return 1;
                else return 0;
            }
            else if(r[i].l == width) {
                vis[i] = 1;
                if(Check(length - r[i].w, width, 2)) return 1;
                else return 0;
            }
            else if(r[i].w == width) {
                vis[i] = 1;
                if(Check(length - r[i].l, width, 1)) return 1;
                else return 0;
            }
        }
    }
    else {
        vis[0] = 1;
        if(r[0].w > width) return 0;
        if(r[0].l == length) {
            if(Check(length, width - r[0].w, 3)) return 1;
            else return 0;
        }
        else if(r[0].l == width) {
            if(Check(length - r[0].w, width, 3)) return 1;
            else return 0;
        }
        else if(r[0].w == width) {
            if(Check(length - r[0].l, width, 3)) return 1;
            else return 0;
        }
        else if(r[0].l < length) {
            int s1_l = length - r[0].l;
            int s1_w = r[0].w;
            int s2_l = r[0].l;
            int s2_w = width - r[0].w;
            for(int i = 1; i < 4; i++) {
                if(r[i].l == s1_l && r[i].w == s1_w ||
                   r[i].l == s1_w && r[i].w == s1_l) {
                    vis[i] = 1;
                    int s3_l = s1_l + s2_l;
                    int s3_w = s2_w;
                    if(Check(s3_l, s3_w, 2)) return 1;
                    else return 0;
                }
                else if(r[i].l == s2_l && r[i].w == s2_w ||
                        r[i].l == s2_w && r[i].w == s2_l) {
                    vis[i] = 1;
                    int s3_l = s1_l;
                    int s3_w = s1_w + s2_w;
                    if(Check(s3_l, s3_w, 2)) return 1;
                    else return 0;
                }
            }
        }
    }

    return 0;
}

bool cmp(Rec a, Rec b)
{
    return a.l > b.l;
}

int main()
{
    int t;
    scanf("%d", &t);
    int length, width;

    while(t--) {
        int sum = 0;
        for(int i = 0; i < 4; i++) {
            scanf("%d %d", &r[i].l, &r[i].w);
            if(r[i].l < r[i].w) swap(r[i].l, r[i].w);
            sum += r[i].l * r[i].w;
        }
        sort(r, r+4, cmp);
        bool flag = 0;
        for(int i = 1; i <= sqrt(sum); i++) {
            if(sum % i == 0) {
                length = sum / i;
                width = i;
                memset(vis, 0, sizeof(vis));
                if(Check(length, width, 4)) {
                    flag = 1;
                    break;
                }
            }
        }
        if(flag) printf("Yes %d %d\n", length, width);
        else printf("No\n");
    }

    return 0;
}
View Code

 

posted @ 2015-11-16 13:34  Quinte  阅读(668)  评论(0编辑  收藏  举报