USACO1.4.1Packing Rectangles解题报告

原题链接: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;
}






          





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值