原题链接:http://cerberus.delos.com:791/usacoprob2?a=eKxwxMvd2mt&S=packrec
解题思路:求出每种摆放方式可能的面积,然后求这些面积的最小值。
1、分析图,求每一种摆放方式的面积。
显然,题目中给出的六个图是矩形的所有摆放方式(其中第四种和第五种是同一种摆放方式),第1~5个图很容易求出覆盖图形的最小矩形的面积,而第六个
图则要考虑按此摆放方式不能让矩形相互覆盖的问题。对第六个图所示的摆放方式求面积:
以样例4 3 4 4 6 3 5 5说明,将四块摆放如下
1 3
2 4
并将靠中间的四个角对齐,这个例子中是这样的:
3 3 3
1 1 1 1 1 3 3 3
1 1 1 1 1 3 3 3
1 1 1 1 1 3 3 3
1 1 1 1 1 3 3 3
1 1 1 1 1 3 3 3
2 2 2 2 4 4 4 4
2 2 2 2 4 4 4 4
2 2 2 2 4 4 4 4
2 2 2 2
然后把较高的右边这条向下移动一格使各块都靠最底(有些例子是左边或者不移动):
此时计算整体图形的高max(1高+2高,3高+4高)因为接下来要水平移动,不会使高减少
1 1 1 1 1 3 3 3
1 1 1 1 1 3 3 3
1 1 1 1 1 3 3 3
1 1 1 1 1 3 3 3
1 1 1 1 1 3 3 3
2 2 2 2 3 3 3
2 2 2 2 4 4 4 4
2 2 2 2 4 4 4 4
2 2 2 2 4 4 4 4
然后将2 和4 向左移至与1 对齐(将1 和3 向右移是一样的):
需要提前验证是否可以向左移动(满足 2高>=4高)
以及移动是否能缩小宽度((1宽>2宽)or(3宽<4宽))不然移动没有意义
移动之后,整体图形的宽为max(1宽+3宽,2宽+4宽)
如果不移动整体图形的宽为max(1宽,2宽)+max(3宽+4宽)
1 1 1 1 1 3 3 3
1 1 1 1 1 3 3 3
1 1 1 1 1 3 3 3
1 1 1 1 1 3 3 3
1 1 1 1 1 3 3 3
2 2 2 2 0 3 3 3
2 2 2 2 4 4 4 4
2 2 2 2 4 4 4 4
2 2 2 2 4 4 4 4
移动完就好了。
2、对矩形进行全排列,然后放到相应的位置。
全排列分两步:
首先要对四个矩形的顺序进行全排列,可形成4!=24种排序,其实要对矩形的摆放方式进行全排列(即在某个位置矩形是横着放还是竖着放呢),4!*2^4种排序。
在第一步中已得出各种摆放方式的面积公式,此时只需代入题目中的数据即可求得面积。
3、记录最小面积及其长和宽。
注意:(1)最小面积容易记录,但是在记录其长和宽是应注意不能重复记录,而且一旦最小面积改变了,之前记录的长和宽就都作废了。
(2)输出长和宽之前要对其进行排序,而且要短边在前,长边在后。
代码实现:
/*
ID: supersnow0622
PROG: packrec
LANG: C++
*/
#include <iostream>
#include <fstream>
#include<memory.h>
#include<algorithm>
#include <string>
using namespace std;
struct Rectangle
{
int width;
int length;
};
Rectangle r[4],rec,recorder[50];
int MIN=1000000,Count=0;
void record()
{
int area=rec.length*rec.width;
if(rec.length>rec.width)
swap(rec.length,rec.width);
if(MIN>area)
{
MIN=area;
memset(recorder,0,sizeof(recorder));
Count=0;
recorder[Count].length=rec.length;
recorder[Count++].width=rec.width;
}
if(MIN==area)
{
int i;
for(i=0;i<Count;i++)
{
if(recorder[i].length==rec.length)
break;
}
if(i==Count)
{
recorder[Count].length=rec.length;
recorder[Count++].width=rec.width;
}
}
}
int getMax(int a,int b)
{
return a>b?a:b;
}
void cal()
{
//case 1
rec.length=0;rec.width=0;
for(int i=0;i<4;i++)
{
rec.length+=r[i].length;
rec.width=getMax(rec.width,r[i].width);
}
record();
//case 2
rec.length=0;rec.width=0;
for(int i=0;i<3;i++)
{
rec.length+=r[i].length;
rec.width=getMax(rec.width,r[i].width);
}
rec.length=getMax(rec.length,r[3].length);
rec.width+=r[3].width;
record();
//case 3
rec.length=getMax(r[0].length+r[1].length,r[2].length)+r[3].length;
rec.width=getMax(r[0].width,r[1].width)+r[2].width;
rec.width=getMax(rec.width,r[3].width);
record();
//case 4 5
rec.length=r[0].length+getMax(r[1].length,r[2].length)+r[3].length;
rec.width=getMax(r[0].width,r[3].width);
rec.width=getMax(rec.width,r[1].width+r[2].width);
record();
//case 6
rec.width=getMax(r[0].width+r[2].width,r[1].width+r[3].width);
if(r[0].width>=r[1].width&&(r[2].length>r[0].length||r[3].length<r[1].length))
rec.length=getMax(r[2].length+r[3].length,r[0].length+r[1].length);
else
rec.length=getMax(r[0].length,r[2].length)+getMax(r[1].length,r[3].length);
record();
}
void swap(int *a,int *b)
{
int m;
m = *a;
*a = *b;
*b = m;
}
void Rotate(int k)
{
if (k == 4)
cal();
else
{
Rotate(k+1); swap(r[k].length, r[k].width);
Rotate(k+1); swap(r[k].length, r[k].width);
}
}
void Permutate(int k)
{
if (k == 4) Rotate(0);
else
{
for (int i = k; i < 4; ++i)
{
swap(r[k], r[i]);
Permutate(k+1);
swap(r[k], r[i]);
}
}
}
int cmp(Rectangle r1,Rectangle r2)
{
if(r1.length==r2.length)
return r1.width<r2.width;
else
return r1.length<r2.length;
}
int main() {
ofstream fout ("packrec.out");
ifstream fin ("packrec.in");
for(int i=0;i<4;i++)
cin>>r[i].length>>r[i].width;
Permutate(0);
cout<<MIN<<endl;
sort(recorder,recorder+Count,cmp);
for(int i=0;i<Count;i++)
cout<<recorder[i].length<<" "<<recorder[i].width<<endl;
return 0;
}