USACO Section 1.4 Packing Rectangles

/*
ID: lucien23
PROG: packrec
LANG: C++
*/

/*
 *深度优先遍历,找出最优解
 *此题是我做USACO到目前为止花时间最多的
 *很郁闷
 **/

#include<iostream>
#include<fstream>
#include<vector>
#include<algorithm>
using namespace std;

typedef struct Rectangle
{
	int width;
	int height;
}Rectangle;

bool comparer1(Rectangle rect1,Rectangle rect2)
{
	return rect1.height*rect1.width<rect2.height*rect2.width;
}

bool comparer2(Rectangle rect1,Rectangle rect2)
{
	return rect1.width<rect2.width;
}

int main()
{
	ifstream infile("packrec.in");
	ofstream outfile("packrec.out");
	if(!infile || !outfile)
	{
		cout<<"file operation failure!"<<endl;
		return -1;
	}

	Rectangle rects[4];
	int width,height;
	for (int i=0;i<4;i++)
	{
		infile>>width>>height;
		rects[i].width=min(width,height);
		rects[i].height=max(width,height);
	}

	//测试6种基本布局(实际只有5中,4,5是相同的)
	//对每一种布局依次遍历每种矩阵的摆放方式
	// 每个矩阵都可能旋转90度,共4!*2^4=384种
	// 找出最小的大矩阵
	vector<Rectangle> vectorRect;
	Rectangle rect;
	for (int i=0;i<4;i++)
	{
		int icount=1;
		while(icount<=2){
			if(icount==2)//矩阵旋转90度
			{
				int temp=rects[i].height;
				rects[i].height=rects[i].width;
				rects[i].width=temp;
			}

			for (int j=0;j<4;j++)
			{
				if(i==j)
					continue;

				int jcount=1;
				while(jcount<=2){
					if(jcount==2)
					{
						int temp=rects[j].height;
						rects[j].height=rects[j].width;
						rects[j].width=temp;
					}

					for (int k=0;k<4;k++)
					{
						if(i==k || j==k)
							continue;

						int kcount=1;
						while(kcount<=2){
							if(kcount==2)
							{
								int temp=rects[k].height;
								rects[k].height=rects[k].width;
								rects[k].width=temp;
							}

							for (int t=0;t<4;t++)
							{
								if(i==t || j==t || k==t)
									continue;

								int tcount=1;
								while(tcount<=2){
									if(tcount==2)
									{
										int temp=rects[t].height;
										rects[t].height=rects[t].width;
										rects[t].width=temp;
									}

									//布局一
									height=max(max(max(rects[i].height,rects[j].height),rects[k].height),rects[t].height);
									width=rects[i].width+rects[j].width+rects[k].width+rects[t].width;
									rect.height=max(height,width);
									rect.width=min(height,width);
									vectorRect.push_back(rect);

									//布局二
									if(rects[t].height>rects[j].width+rects[k].width)
									{
										height=max(max(rects[i].height,rects[j].height),rects[k].height)+rects[t].width;
										width=max(rects[i].width+rects[j].width+rects[k].width,rects[t].height);
										rect.height=max(height,width);
										rect.width=min(height,width);
										vectorRect.push_back(rect);
									}

									//布局三
									if(rects[t].height>rects[j].width)
									{
										height=max(max(rects[i].height,rects[j].height)+rects[t].width,rects[k].height);
										width=max(rects[i].width+rects[j].width,rects[t].height)+rects[k].width;
										rect.height=max(height,width);
										rect.width=min(height,width);
										vectorRect.push_back(rect);
									}

									//布局四
									height=max(max(rects[i].height,rects[k].height),rects[j].height+rects[t].height);
									width=max(rects[j].width,rects[t].width)+rects[i].width+rects[k].width;
									rect.height=max(height,width);
									rect.width=min(height,width);
									vectorRect.push_back(rect);

									//布局五,最麻烦的,左右两边其实是对称的情况,所以只考虑一边就行
									if(rects[k].height>=rects[t].height)
									{
										if(rects[i].height+rects[t].height>rects[k].height && rects[i].width<=rects[t].width)
										{//这个条件通过镜像反射代表了两个条件
											width=max(rects[i].width+rects[j].height,rects[k].width+rects[t].width);
										}
									}else if(rects[j].width+rects[k].height<=rects[t].height){
										width=max(max(rects[j].height,rects[k].width)+rects[t].width,rects[i].width);
									}else{
										width=max(rects[i].width,rects[t].width)+max(rects[j].height,rects[k].width);
									}
									height=max(rects[i].height+rects[t].height,rects[j].width+rects[k].height);
									
									rect.height=max(height,width);
									rect.width=min(height,width);
									vectorRect.push_back(rect);

									tcount++;
								}
							}
							kcount++;
						}
					}
					jcount++;
				}
			}
			icount++;
		}
	}
	

	sort(vectorRect.begin(),vectorRect.end(),comparer1);//按面积从小到大排序
	vector<Rectangle>::iterator it=vectorRect.begin();
	for (it++;it!=vectorRect.end();it++)
	{
		if(it->height*it->width > (it-1)->height*(it-1)->width)
			break;
	}
	sort(vectorRect.begin(),it,comparer2);//将最小面积的方案按宽度从小到大排序

	vector<Rectangle>::iterator it2=vectorRect.begin();
	outfile<<it2->height*it2->width<<endl;
	outfile<<it2->width<<" "<<it2->height<<endl;
	for (it2++;it2!=it;it2++)
	{
		if(it2->width==(it2-1)->width)
			continue;
		outfile<<it2->width<<" "<<it2->height<<endl;
	}

	infile.close();
	outfile.close();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值