USACO 1.4 packrec

本文讨论了一个涉及复杂几何排列的编程挑战,通过详细分析和模拟过程,作者成功解决了该问题。文章中提到了24种排列方式和16种不同的矩形定向方法,最终通过生成所有可能的排列组合并进行比较,找到最小的矩形尺寸。经过多次测试验证,程序正确无误地产生了所有预期答案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

变态题啊~~~

This program is straightforward(朴素的模拟), but a bit long due to the geometry involved.

There are 24 permutations of the 4 rectangles, and for each permutation, 16 different ways to orient them. We generate all such orientations of permutations, and put the blocks together in each of the 6 different ways, recording the smallest rectangles we find.

——USACO analysis

改了很多遍,错误大都出在最后一种情况上,没办法,于是直接找来ANALYSIS标程上的这段模拟套上就好了……

Compiling...
Compile: OK

Executing...
   Test 1: TEST OK [0.000 secs, 2144 KB]
   Test 2: TEST OK [0.000 secs, 2144 KB]
   Test 3: TEST OK [0.000 secs, 2144 KB]
   Test 4: TEST OK [0.000 secs, 2144 KB]
   Test 5: TEST OK [0.000 secs, 2144 KB]
   Test 6: TEST OK [0.000 secs, 2144 KB]
   Test 7: TEST OK [0.000 secs, 2144 KB]
   Test 8: TEST OK [0.000 secs, 2144 KB]
   Test 9: TEST OK [0.000 secs, 2144 KB]
   Test 10: TEST OK [0.000 secs, 2144 KB]
   Test 11: TEST OK [0.000 secs, 2144 KB]
   Test 12: TEST OK [0.000 secs, 2144 KB]
   Test 13: TEST OK [0.000 secs, 2144 KB]
   Test 14: TEST OK [0.000 secs, 2144 KB]
   Test 15: TEST OK [0.000 secs, 2144 KB]
   Test 16: TEST OK [0.000 secs, 2144 KB]
   Test 17: TEST OK [0.000 secs, 2144 KB]
   Test 18: TEST OK [0.000 secs, 2144 KB]
   Test 19: TEST OK [0.000 secs, 2144 KB]
   Test 20: TEST OK [0.000 secs, 2144 KB]
   Test 21: TEST OK [0.000 secs, 2144 KB]

All tests OK.

Your program ('packrec') produced all correct answers! This is your submission #7 for this problem. Congratulations!

/*
ID:zizz-zi1
LANG:C
TASK:packrec
*/

#include <stdio.h>
typedef struct rect rect;
struct rect{
	int l;
	int w;
};
int flag[4]={0};
rect r[4];
int ans,ansn,answ[100],ansl[100],c[100];
int max(int a,int b)
{
	return a>b?a:b;
}

int min(int a,int b)
{
	return a<b?a:b;;
}

void qsort(int l,int r)
{
	int t,i=l,j=r,m=answ[(i+j)/2];
	while (i<=j){
		while(answ[i]<m) i++;
		while(answ[j]>m) j--;
		if(i<=j){
			t=answ[i];
			answ[i]=answ[j];
			answ[j]=t;
			t=ansl[i];
			ansl[i]=ansl[j];
			ansl[j]=t;
			i++;
			j--;
		}
	}
	if(i<r) qsort(i,r);
	if(l<j) qsort(l,j);
}

void checkans(int l,int w,int cc,rect *r)      //cc, r 这都是为了调试
{
	if (l*w<ans){
		ans=l*w;
		ansn=1;
		answ[ansn]=min(w,l);
		ansl[ansn]=max(w,l);
		c[ansn]=cc;
	}
	else
		if(l*w==ans){
			ansn++;
			answ[ansn]=min(w,l);
			ansl[ansn]=max(w,l);
		}
}

void check(rect *r)
{
	checkans(max(max(r[0].l,r[1].l), max(r[2].l,r[3].l)),r[0].w+r[1].w+r[2].w+r[3].w,1,r);
	checkans(max(r[0].l+r[1].l,r[2].l)+r[3].l,max(max(r[0].w+r[2].w,r[1].w+r[2].w),r[3].w),2,r);
	checkans(max(r[0].l,r[1].l)+r[2].l+r[3].l,max(max(r[0].w+r[1].w,r[2].w),r[3].w),3,r);
	checkans(max(r[0].l+r[1].l+r[2].l,r[3].l),max(max(r[0].w,r[1].w),r[2].w)+r[3].w,4,r);
//下面这种情况想不到自己的方法了,直接套用标程
	int l,w;
	l=max(r[0].l+r[2].l,r[1].l+r[3].l);
	w=r[0].w+r[1].w;
	if(r[0].l<r[1].l)
		w=max(w,r[2].w+r[1].w);
	if(r[0].l+r[2].l>r[1].l)
		w=max(w,r[2].w+r[3].w);
	if(r[1].l<r[0].l)
		w=max(w,r[0].w+r[3].w);
	w=max(w,r[2].w);
	w=max(w,r[3].w);
	checkans(l,w,5,r);
}

void rotate(rect *tmp,int deep)    //长宽旋转互换,回溯
{
	if(deep==4)
		check(tmp);
	else{
		rotate(tmp,deep+1);
		int t;
		t=tmp[deep].l;
		tmp[deep].l=tmp[deep].w;
		tmp[deep].w=t;
		rotate(tmp,deep+1);
		t=tmp[deep].l;
		tmp[deep].l=tmp[deep].w;
		tmp[deep].w=t;
	}
}

int permute(rect *tmp,int deep)    //不同矩形顺序,或者说是编号,深搜;标程这里方法很漂亮
{
	int i;
	if(deep==4){
		rotate(tmp,0);
		return 0;
	}
	for(i=0;i<4;i++)
		if(flag[i]==0){
			tmp[deep]=r[i];
			flag[i]=1;
			permute(tmp,deep+1);
			flag[i]=0;
		}
	return 0;
}

int main(void)
{
	FILE *fin,*fout;
	fin=fopen("packrec.in","r");
	fout=fopen("packrec.out","w");
	int tmpl=0,tmpw=0,i,j;
	rect tmp[4];
	for(i=0;i<4;i++){
		fscanf(fin,"%d %d",&r[i].l,&r[i].w);
		tmpl+=r[i].l;
		tmpw+=r[i].w;
	}
	ansn=1;
	ansl[ansn]=max(tmpl,tmpw);
	answ[ansn]=min(tmpl,tmpw);
	ans=ansl[ansn]*answ[ansn];

	permute(tmp,0);
	qsort(1,ansn);

	fprintf(fout,"%d\n",ans);
	tmpw=-1;
	for(i=1;i<=ansn;i++)
		if(answ[i]!=tmpw){
			fprintf(fout,"%d %d\n",answ[i],ansl[i]);
			tmpw=answ[i];
		}
	fclose(fin);fclose(fout);
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值