USACO:1.4.1 Packing Rectangles 鋪放矩形塊(IOI 95)解析


USACO:1.4.1 Packing Rectangles 鋪放矩形塊(IOI 95) 解析

題目描述:

       給定4 個矩形塊,找出一個最小的封閉矩形將這4 個矩形塊放入,但不得相互重疊。所謂最小矩形指該矩形面積最小。所有4 個矩形塊的邊都與封閉矩形的邊相平行,圖1 示出了鋪放4 個矩形塊的6 種方案.這6 種方案僅只是可能的基本鋪放方案。因為其它方案能由基本方案通過旋轉和鏡像反射得到。可能存在滿足條件且有着同樣面積的各種不同的封閉矩形,你應該輸出所有這些封閉矩形的邊長。


圖1. 4種基本鋪放方式
PROGRAM NAME: packrec

輸入格式:

        共有4 行,每一行用兩個正整數來表示一個給定的矩形塊的兩個邊長。矩形塊的每條邊的邊長范圍最小是1,最大是50。

SAMPLE INPUT (file packrec.in)
1 2
2 3
3 4
4 5

輸出格式:
        總行數為解的總數加1。第一行是一個整數,代表封閉矩形的最小面積(子任務A)。接下來的每一行都表示一個解,由數P 和數Q 來表示,並且P≤Q(子任務B)。這些行必須根據P 的大小按升序排列,P小的行在前,大的在后,且所有行都應是不同的。
SAMPLE OUTPUT (file packrec.out)
40
4 10
5 8


解題思路:

        我看到這個題目后,也是不之所措。最后也沒有做出來。這里,我只能和大家一起解讀大牛寫的代碼。看過大牛 MasterRay寫的程序后,我發現原理也不是很難(呵呵,不是那么容易~)。

       首先,理解題意,題目描述中很明確---只有6種基本的鋪放方式。我們可以把這6種鋪放情況都枚舉出來,無非就是我們先把鋪放的位置編號(默認假定),把所有4個矩形全排列。然后,對於case1-5,so easy!(其中4、5其實是一種情況)。而case 6 就需要我們考慮各種接觸情況了。。。

       注意,矩形是有方向的,因為兩個邊長一般不相等,矩形有兩個方向。所以,全排時還要考慮方向問題。


/*
ID: MasterRay
LANG: C++
TASK: packrec
*/

#include <algorithm>
#include <climits>
#include <cstdio>
using namespace std;

bool flag[10] = {};
int res[101], res_area = INT_MAX;
struct rectangle
{
int x, y;
}a[4], rec;

void Record()
{
if (rec.x*rec.y < res_area)
{
res_area = rec.x*rec.y;
fill_n(res+1, 100, 0);
}
if (rec.x*rec.y == res_area)
res[min(rec.x, rec.y)] = 1;
}

void Calc()
{
//case 1
rec.x = 0; rec.y = 0;
for (int i = 0; i < 4; ++i)
{
rec.x += a[i].x;
if (a[i].y > rec.y) rec.y = a[i].y;
}
Record();
//case 2
rec.x = 0; rec.y = 0;
for (int i = 1; i < 4; ++i)
{
rec.x += a[i].x;
if (a[i].y > rec.y) rec.y = a[i].y;
}
if (a[0].x > rec.x) rec.x = a[0].x;
rec.y += a[0].y;
Record();
//case 3
rec.x = max(a[0].x+a[1].x, a[2].x)+a[3].x;
rec.y = max(max(a[0].y, a[1].y)+a[2].y, a[3].y);
Record();
//case 4, 5
rec.x = a[0].x+max(a[1].x, a[2].x)+a[3].x;
rec.y = max(max(a[0].y, a[1].y+a[2].y), a[3].y);
Record();
//case 6
rec.x = a[0].x+a[1].x;
rec.y = max(a[0].y+a[2].y, a[1].y+a[3].y);
if (a[0].y < a[1].y)
rec.x = max(rec.x, a[2].x+a[1].x);
if (a[0].y+a[2].y > a[1].y)
rec.x = max(rec.x, a[2].x+a[3].x);
if (a[1].y < a[0].y)
rec.x = max(rec.x, a[0].x+a[3].x);
rec.x = max(rec.x, a[2].x);
rec.x = max(rec.x, a[3].x);
Record();
}

void Rotate(int k)
{
if (k == 4) Calc();
else
{
Rotate(k+1); swap(a[k].x, a[k].y);
Rotate(k+1); swap(a[k].x, a[k].y);
}
}

void Permutate(int k)
{
if (k == 4) Rotate(0);
else
{
for (int i = k; i < 4; ++i)
{
swap(a[k], a[i]);
Permutate(k+1);
swap(a[k], a[i]);
}
}
}

int main()
{
freopen("packrec.in", "r", stdin);
freopen("packrec.out", "w", stdout);
for (int i = 0; i < 4; ++i)
scanf("%d%d", &a[i].x, &a[i].y);
Permutate(0);
printf("%d\n", res_area);
for (int i = 1; i <= 100; ++i)
if (res[i])
printf("%d %d\n", i, res_area/i);
}


            大牛 MasterRay,請原諒我造次引用和解讀你的代碼!我向您道歉!



       由於自身是初學者,編程能力有限,未達到程序員的水平,可能誤導大家,請大家甄讀;文字編輯一般,文中會有言辭不當。博文中的錯誤和不足敬請讀者批評指正。



注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com