USACO 6.2.2 Packing Rectangles 暴力模拟

http://train.usaco.org/usacoprob2?a=Hfv8bxVT1Ac&S=packrec

题目大意:给四个矩形(用长和宽表示),求能够将他们全部包起来的最小矩形面积和边长(按照较短边升序输出)

※给了四个矩形的六种基本摆放方法:


原本以为又是什么巧妙的构造法,但是看他给了六种基本摆放方法再估算一下所有的可能性感觉可以直接模拟,事实确实如此

现在只留下了两个问题:1、图四和图五有什么区别 2、图六的外围矩形面积该如何计算

1、图四和图五没有任何区别

2、图六的计算我想了很久,一开始想用左右两组的高度确定高度,用上下两组的宽度确定宽度,但尝试之后发现可能会有斜对角矩形碰撞的问题

void form6()
{
    int width, height;
    width = max(cur[0].width+cur[1].width, cur[2].width+cur[3].width);
    height = max(cur[0].height+cur[2].height, cur[1].height+cur[3].height);
    judge(width, height);

    width = max(cur[0].width+cur[3].width, cur[1].width+cur[2].width);
    height = max(cur[0].height+cur[1].height, cur[3].height+cur[2].height);
    judge(width, height);

    width = max(cur[0].width+cur[3].width, cur[2].width+cur[1].width);
    height = max(cur[0].height+cur[2].height, cur[3].height+cur[1].height);
    judge(width, height);
}

后来想通过平移使上下两组被一条水平线分割,但在有些情况下这样求得的不是最小矩形(但是能过前2/3样例)

特殊情况(上左5*5,上右3*6,下左4*4,下右4*3)

void form6()
{
    int width, height;
    for(int i = 0; i < 4; ++i){
        for(int k = 0; k < 4; ++k){
            if(k == i) continue;
            width = 0; height = 0;
            for(int j = 0; j < 4; ++j){
                if(j == i || j == k) continue;
                width += cur[j].width;
                height = max(height, cur[j].height);
            }
            width = max(width, (cur[k].width)+cur[i].width);
            height += max(cur[k].height, cur[i].height);
            judge(width, height);
        }
    }
}

看了题解才恍然大悟,我之前太拘泥于整体性的考虑,想要得到一个普适的几何公式,这样就要考虑很多种碰撞的可能性,简直就是庸人自扰。题目给的提示已经很明显了,将方块分为左右两组,以左侧为参照,根据右侧两块的高低,会有不同的两两碰撞情况,通过分类讨论的方式就只需要解决一些简单明了的情况了

参考:http://blog.sina.com.cn/s/blog_5f5ada1a0100qhjr.html

※注意:即使在某一块不和其他块碰撞的情况下,它的宽度也应该被纳入计算

void form6()
{
    int width, height;
    for(int i = 0; i < 4; ++i){
        for(int k = 0; k < 4; ++k){
            if(k == i) continue;
            width = 0; height = 0;
            for(int j = 0; j < 4; ++j){
                if(j == i || j == k) continue;
                int l = 6-i-j-k;
                height = max(cur[i].height+cur[k].height, cur[j].height+cur[l].height);
                /*
                i   j
                k   l
                */
                if(cur[j].height+cur[l].height <= cur[k].height) width = max(cur[i].width, max(cur[j].width, cur[l].width)+cur[k].width);
                else if(cur[j].height+cur[l].height > cur[k].height && cur[l].height < cur[k].height) width = max(cur[l].width+cur[k].width, max(cur[i].width, cur[k].width)+cur[j].width);
                else if(cur[l].height >= cur[k].height && cur[l].height < cur[k].height + cur[i].height) width = max(cur[j].width+cur[i].width, max(cur[i].width, cur[k].width)+cur[l].width);
                else if(cur[l].height >= cur[k].height + cur[i].height) width = max(cur[j].width, max(cur[i].width, cur[k].width)+cur[l].width);
                judge(width, height);
            }
        }
    }
}


全部代码如下:

/*
ID: frontie1
TASK: packrec
LANG: C++
*/
#include <iostream>
#include <cstdio>

using namespace std;

const int INFI = 0x3f3f3f3f;

struct rectangle
{
    int width;
    int height;

    rectangle rota()
    {
        rectangle output;
        output.width = height;
        output.height = width;
        return output;
    }

    bool operator<=(rectangle &obj)
    {
        return (width <= obj.width);
    }

    bool operator==(rectangle &obj)
    {
        return (width == obj.width);
    }
    void print()
    {
        if(width > height) return;
        cout << width << ' ' << height << endl;
    }
};

rectangle ori[4], cur[4];
int output_area = INFI;
rectangle output[100];
int cnt = 0;

void judge(int w, int h)
{
    if(w*h <= output_area){
        if(w*h < output_area){
            output_area = w*h;
            cnt = 0;
        }
        output[cnt].width = min(w, h);
        output[cnt].height = max(w, h);
        ++cnt;
    }
}

void makeposition(int num)
{
    for(int i = 0; i < 4; ++i){
        if((num >> i) & 1) cur[i] = ori[i].rota();
        else cur[i] = ori[i];
    }
}

void form1()
{
    int width = 0, height = 0;
    for(int i = 0; i < 4; ++i){
        width += cur[i].width;
        height = max(height, cur[i].height);
    }
    judge(width, height);
}

void form2()
{
    int width, height;
    for(int i = 0; i < 4; ++i){
        width = 0; height = 0;
        for(int k = 0; k < 4; ++k){
            if(k == i) continue;
            width += cur[k].width;
            height = max(height, cur[k].height);
        }
        width = max(width, cur[i].width);
        height += cur[i].height;
        judge(width, height);
    }
}

void form3()
{
    int width, height;
    for(int i = 0; i < 4; ++i){
        for(int k = 0; k < 4; ++k){
            if(k == i) continue;
            width = 0; height = 0;
            for(int j = 0; j < 4; ++j){
                if(j == i || j == k) continue;
                width += cur[j].width;
                height = max(height, cur[j].height);
            }
            width = max(width, cur[k].width);
            height += cur[k].height;
            width += cur[i].width;
            height = max(height, cur[i].height);
            judge(width, height);
        }
    }
}

void form4()
{
    int width, height;
    for(int i = 0; i < 4; ++i){
        for(int k = 0; k < 4; ++k){
            if(k == i) continue;
            width = 0; height = 0;
            for(int j = 0; j < 4; ++j){
                if(j == i || j == k) continue;
                height += cur[j].height;
                width = max(width, cur[j].width);
            }
            height = max(height, cur[k].height);
            width += cur[k].width;
            width += cur[i].width;
            height = max(height, cur[i].height);
            judge(width, height);
        }
    }
}

void form6()
{
    int width, height;
    for(int i = 0; i < 4; ++i){
        for(int k = 0; k < 4; ++k){
            if(k == i) continue;
            width = 0; height = 0;
            for(int j = 0; j < 4; ++j){
                if(j == i || j == k) continue;
                int l = 6-i-j-k;
                height = max(cur[i].height+cur[k].height, cur[j].height+cur[l].height);
                /*
                i   j
                k   l
                */
                if(cur[j].height+cur[l].height <= cur[k].height) width = max(cur[i].width, max(cur[j].width, cur[l].width)+cur[k].width);
                else if(cur[j].height+cur[l].height > cur[k].height && cur[l].height < cur[k].height) width = max(cur[l].width+cur[k].width, max(cur[i].width, cur[k].width)+cur[j].width);
                else if(cur[l].height >= cur[k].height && cur[l].height < cur[k].height + cur[i].height) width = max(cur[j].width+cur[i].width, max(cur[i].width, cur[k].width)+cur[l].width);
                else if(cur[l].height >= cur[k].height + cur[i].height) width = max(cur[j].width, max(cur[i].width, cur[k].width)+cur[l].width);
                judge(width, height);
            }
        }
    }
}

void quicksort(int st, int ed)
{
    if(st >= ed) return;
    int lo = st, hi = ed;
    rectangle tem = output[lo];
    while(lo < hi){
        while(lo < hi && tem <= output[hi]) --hi;
        output[lo] = output[hi];
        while(lo < hi && output[lo] <= tem) ++lo;
        output[hi] = output[lo];
    }
    output[lo] = tem;
    quicksort(st, lo-1);
    quicksort(lo+1, ed);
}

int main()
{
    freopen("packrec.in", "r", stdin);
    freopen("packrec.out", "w", stdout);

    for(int i = 0; i < 4; ++i){
        cin >> ori[i].width >> ori[i].height;
    }

    for(int i = 0; i < 16; ++i){
        makeposition(i);
        form1();
        form2();
        form3();
        form4();
        form6();
    }

    cout << output_area << endl;
    quicksort(0, cnt-1);

    output[0].print();
    for(int i = 1; i < cnt; ++i){
        if(output[i] == output[i-1]) continue;
        else output[i].print();
    }

    return 0;
}

备注:可以注意到我在打印结果的时候加了一条(width < height)的判断,其实是多余的,因为在judge()函数里已经保证了这个性质,但是如果没有这条语句我会在第二个样例中发生错误,更诡异的是在本地跑的时候不会有这样的问题,实在是令人头大




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值