Packing Rectangles

部分内容转自:http://starforever.blog.hexun.com/2097115_d.html


题意:给定四个矩形,矩形在平面中只能垂直或者水平放置,而且不能有重叠。求能把这四个矩形都框在里面的封闭矩形的最小面积s。这样的矩形可能不止一个,求出所有这些封闭矩形的边长情况p, q。p<q且p*q=s。输出的结果按照p递增的顺序排列。


解题思路

  1. 完全可以参照http://starforever.blog.hexun.com/2097115_d.html这篇文章中的内容求解。
  2. 文中对矩形的放法进行了布局分类,并且标出了1、2、3、4
  3. 令四个矩形的水平长度分别为w1~w4,垂直长度分别为h1~h4。对四个矩形的边长进行枚举,就能模拟矩形的各种放法(包括横放竖放以及所在的位置),总共会有8*6*4*2=384种取法。
  4. 对384种取法进行遍历,在遍历过程中求出每种取法下各种布局的封闭矩形面积,并更新最小值。同时将封闭矩形的变边长存于数组中。
  5. 最后对这个数组进行去重和排序就能得到最终的结果

代码

/*
ID: zc.rene1
LANG: C
PROG: packrec
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<stdarg.h>

int min_area=200*200;
int result_width[8*6*4*2*9];
int result_height[8*6*4*2*9];
int result_index=0;

int max_val(int num, ...){
	va_list ap;
	int i, max=-1, temp;
	
	va_start(ap, num);
	for(i=0; i<num; i++){
		temp=va_arg(ap, int);
		if(max<=temp) max=temp;
	}
	va_end(ap);
	return max;
}

void set_tag_h(int tag[], int h[], int num, int index){
	tag[num]=1;
	
	if(num<4){
		tag[num+4]=1;
		h[index]=num+4;
	}
	else{
		tag[num-4]=1;
		h[index]=num-4;
	}
}

void clear_tag(int tag[], int num){
	tag[num]=0;
	
	if(num<4){
		tag[num+4]=0;
	}
	else{
		tag[num-4]=0;
	}
}

void do_work(int length[], int w[], int h[]){
	int i, width, height, temp_area;
	int w_c[4], h_c[4];

	for(i=0; i<4; i++){
		w_c[i]=length[w[i]];
		h_c[i]=length[h[i]];
	}
	//case1
	width=w_c[0]+w_c[1]+w_c[2]+w_c[3];
	height=max_val(4, h_c[0], h_c[1], h_c[2], h_c[3]);
	temp_area=width*height;
	if(temp_area<=min_area){
		if(temp_area<min_area){
			result_index=0;
		}
		result_width[result_index]=width<height?width:height;
		result_height[result_index]=height>width?height:width;
		result_index++;
		min_area=temp_area;
	}
	//case2
	width=max_val(2, w_c[0]+w_c[1]+w_c[2], w_c[3]);
	height=h_c[3]+max_val(3, h_c[0], h_c[1], h_c[2]);
	temp_area=width*height;
	if(temp_area<=min_area){
		if(temp_area<min_area){
			result_index=0;
		}
		result_width[result_index]=width<height?width:height;
		result_height[result_index]=height>width?height:width;
		result_index++;
		min_area=temp_area;
	}
	//case3
	width=max_val(2, w_c[0], w_c[1])+w_c[2]+w_c[3];
	height=max_val(3, h_c[0]+h_c[1], h_c[2], h_c[3]);
	temp_area=width*height;
	if(temp_area<=min_area){
		if(temp_area<min_area){
			result_index=0;
		}
		result_width[result_index]=width<height?width:height;
		result_height[result_index]=height>width?height:width;
		result_index++;
		min_area=temp_area;
	}
	//case4
	width=w_c[0]+max_val(2, w_c[3], w_c[1]+w_c[2]);
	height=max_val(2, h_c[0], max_val(2, h_c[1], h_c[2])+h_c[3]);
	temp_area=width*height;
	if(temp_area<=min_area){
		if(temp_area<min_area){
			result_index=0;
		}
		result_width[result_index]=width<height?width:height;
		result_height[result_index]=height>width?height:width;
		result_index++;
		min_area=temp_area;
	}
	//case5
	height=max_val(2, h_c[0]+h_c[2], h_c[1]+h_c[3]);
	if(h_c[2]>=(h_c[1]+h_c[3])){
		width=max_val(2, w_c[0], w_c[2]+max_val(2, w_c[1], w_c[3]));	
	}
	else if(h_c[2]>h_c[3]&&h_c[2]<(h_c[1]+h_c[3])){
		width=max_val(3, w_c[0]+w_c[1], w_c[1]+w_c[2], w_c[2]+w_c[3]);	
	}
	else if(h_c[2]==h_c[3]){
		width=max_val(2, w_c[0]+w_c[1], w_c[2]+w_c[3]);
	}
	else if(h_c[2]<h_c[3]&&h_c[3]<(h_c[0]+h_c[2])){
		width=max_val(3, w_c[0]+w_c[1], w_c[0]+w_c[3], w_c[2]+w_c[3]);
	}
	else{
		width=max_val(2, w_c[1], w_c[3]+max_val(2, w_c[0], w_c[2]));
	}
	temp_area=width*height;
	if(temp_area<=min_area){
		if(temp_area<min_area){
			result_index=0;
		}
		result_width[result_index]=width<height?width:height;
		result_height[result_index]=height>width?height:width;
		result_index++;
		min_area=temp_area;
	}
}

void sort_result(){
	int i, j, temp;

	for(j=result_index-1; j>0; j--){
		for(i=0; i<j; i++){
			if(result_width[i]>result_width[i+1]){
				temp=result_width[i];
				result_width[i]=result_width[i+1];
				result_width[i+1]=temp;
				temp=result_height[i];
				result_height[i]=result_height[i+1];
				result_height[i+1]=temp;
			}
		}
	}
}

int main(void){
	FILE *fin=fopen("packrec.in", "r");
	FILE *fout=fopen("packrec.out", "w");

	int length[8], tag[8], w[4], h[4];
	int i, j, k, m, prev=-1;
	
	for(i=0; i<4; i++){
		fscanf(fin, "%d %d", &length[i], &length[4+i]);
	}
	
	memset(tag, 0, 8*sizeof(int));

	for(i=0; i<8; i++){
		w[0]=i;
		set_tag_h(tag, h, i, 0);
		for(j=0; j<8; j++){
			if(tag[j]==1) continue;
			w[1]=j;
			set_tag_h(tag, h, j, 1);
			for(k=0; k<8; k++){
				if(tag[k]==1) continue;
				w[2]=k;
				set_tag_h(tag, h, k, 2);
				for(m=0; m<8; m++){
					if(tag[m]==1) continue;
					w[3]=m;
					set_tag_h(tag, h, m, 3);
					do_work(length, w, h);
					clear_tag(tag, m);
				}
				clear_tag(tag, k);
			}
			clear_tag(tag, j);
		}
		clear_tag(tag, i);
	}
	
	sort_result();
	fprintf(fout, "%d\n", min_area);
	for(i=0; i<result_index; i++){
		if(result_width[i]==prev) continue;
		fprintf(fout, "%d %d\n", result_width[i], result_height[i]);
		prev=result_width[i];
	}
	return 0;
}










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值