USACO Section 1.4 packrec
来源:互联网 发布:淘宝网天猫男装外套 编辑:程序博客网 时间:2024/05/15 07:49
一开始无从下手。后来想着情况也不是很多,可以每种情况都分别枚举,这时位置固定之后,计算长宽就相对简单了。
1. 四个矩形摆放,有多少种最基本的方式? 题目给了6种基本型.我按照 矩形承载的矩形数目 来分类。
(PS:这里我想到离数的 集合划分和等价关系。 只要证明该关系是传递,自反,对称的, 那么利用该关系就能 不重不漏的划分一个集合。
两种摆放是有关系的,如果上方的矩形个数是相同的。似乎三个性质都满足,所以似乎是一个等价关系。虽然关系的这个定义不那么明确。
这样把所有摆放分成了4类, 但是2个矩形的情况有两种无法合并,即下表的3,4。恩,确实是很不成熟的想法。
)
而且枚举的范围无需 A(4,4)! * 16, 四个矩形的全排列,2^4种长宽搭配。
case 1:四个并排,矩形的顺序没有影响,所以只需枚举16种。
case 2: 2个矩形的上下顺序没有影响,另外两个矩形的左右顺序也没有影响,C(2,4)*16 即可
case 3:田字形关键在于对角线,确定一组对角线,另外两块的顺序没有影响。所以只有3种对角线, 3*16种。
case 4:矩形上方的两块的顺序没有影响。另外两块的顺序有影响,所以 C(2,4)*2*16 = 192
case 5:上方的三块顺序没有影响,所以4*16种。
2. 大方向已经定好了,就是写几个函数分别计算这五种情况的enclosing rectangle的长宽。接下来是处理16种长宽搭配,
长宽搭配的不同就是把给定位置上的矩形旋转90度,或者说交换长宽。可以使用循环,递归,或者枚举处理16种情况。
我用的是循环。0~15, 四位二进制表示中,1代表旋转,0代表不旋转。
3. 计算 enclosing rectangle时,case 3田字形特别麻烦,要判断重叠。
剩下的就是仔细考虑如何计算长宽, 还有debug了。
#include <stdlib.h>#include <stdio.h>#include <string.h>#include <ctype.h>struct rectangle{int a, b;}; typedef struct rectangle Rectangle;Rectangle solution[450]; //enclosing rectangleint count=0; // number of possible solutionint minL=51, minW=51, minArea=20000;int Max( int a, int b){return (a>b)? a:b;}Rectangle rotate_90( Rectangle r ){Rectangle t = { .a = r.b, .b = r.a};return t;}void setConbination( Rectangle* des, const Rectangle* ori, int indictator){int j=0;for(; j<4; j++) des[j] = (indictator&(1<<j))? rotate_90(ori[j]) : ori[j]; }void setSolution( int L, int W ){if( L*W > minArea ) return;minArea = L*W;int t;if( L > W ) { t=L; L=W; W=t; } //output should sort by Lsolution[count].a = L ;solution[count].b = W;count++;} // combination 1111, four rectangles stand side by side void case1( const Rectangle* ori ){Rectangle r[4];int i, j,L, W;for( i=0; i<16; i++){ // i的低四位0000-1111 代表16种长宽搭配, 1代表旋转,0代表不转 L=W=0;setConbination( r, ori, i);for( j=0; j<4; j++){L += r[j].a;W = Max( W, r[j].b );}setSolution( L, W ); }} // combination 112 , 6 kinds /* _ _ _|a|b|c|| | |_||_|_|d|*/void case2( const Rectangle* ori ){const int numCase=6; //6 basic combinations, indictator[3][1] means rec indictator[3][1]int indicator[][4]={ // needs puting in the positong b of 3rd type.( 0123 means abcd ){0, 1, 2, 3}, {0, 2, 1, 3}, {0, 3, 1, 2},{1, 2, 0, 3}, {1, 3, 0, 2}, {2, 3, 0, 1},};int (*p)[4] = indicator;Rectangle r[4];int i,k, L,W;for( k=0; k<numCase; k++){ for( i=0; i<16; i++){L=W=0;setConbination( r, ori, i);L = r[p[k][0]].a + r[ p[k][1] ].a + Max( r[ p[k][2] ].a, r[ p[k][3] ].a );W = Max( r[p[k][0]].b, Max( r[p[k][1]].b, r[ p[k][2] ].b + r[ p[k][3] ].b ) );setSolution( L, W );}}}// 田字摆放,只有三种本质不同的组合(对角线), 注意重叠问题 /*dcab32 23 3101 01 02*/void case3( const Rectangle* ori ){const int numCase = 3;int indicator[][4]={ {0, 1, 2, 3}, {0, 1, 3, 2}, {0, 2, 1, 3},};Rectangle r[4];int i,k, L,W;int a, b, c, d;for( k=0; k<numCase; k++){a = indicator[k][0]; b=indicator[k][1]; c = indicator[k][2]; d=indicator[k][3];for( i=0; i<16; i++){L=W=0;setConbination( r, ori, i);//Too simple! It is Buggy!! overlap will happen and compute a too small result. //L = Max( r[].a + r[p[k][1]].a, r[p[k][2]].a + r[p[k][3]].a );//W = Max( r[p[k][0]].b + r[p[k][3]].b, r[p[k][1]].b + r[p[k][2]].b );if( r[a].b > r[b].b ){ //奠基的两块分高低。 低的那块先填 L = r[a].a + Max( r[b].a, r[c].a); // b比较矮,填上c块L = Max( L, r[d].a+r[c].a );// 填上d块 }else{L = r[b].a + Max( r[a].a, r[d].a); //a比较矮,所以先填上d块。 L = Max( L, r[c].a+r[d].a );// 填上c块}W = Max( r[a].b+r[d].b, r[c].b+r[b].b ); setSolution( L, W );//printf("## %d %d %d %d %d %d %d\n", L, W, a, b, c, d, i); }}}/*C(2,4)*2 = 12ab 顺序有影响 , cd 没有 _ _ _| |d|c||a|_|_||_|b__|*/void case4( const Rectangle* ori ){const int numCase = 12; int indicator[][4]={ //indicator[k][0] {0, 1, 2, 3}, {0, 2, 1, 3}, {0, 3, 1, 2}, {1, 0, 2, 3}, {2, 0, 1, 3}, {3, 0, 1, 2},{1, 2, 0, 3}, {1, 3, 0, 2}, {2, 3, 0, 1},{2, 1, 0, 3}, {3, 1, 0, 2}, {3, 2, 0, 1}, };int (*p)[4] = indicator;Rectangle r[4];int i,k, L,W;for( k=0; k<numCase; k++){for( i=0; i<16; i++){L=W=0;setConbination( r, ori, i);if( r[p[k][1]].b < r[p[k][0]].b ) //a块比b矮 L = r[p[k][0]].a + Max( r[p[k][1]].a, r[ p[k][2]].a+r[ p[k][3]].a );elseL = Max( r[p[k][0]].a + r[p[k][1]].a, r[ p[k][2]].a+r[ p[k][3]].a );W = Max( r[p[k][0]].b, r[p[k][1]].b + Max( r[p[k][2]].b, r[p[k][3]].b ) );setSolution( L, W );//printf("## %d %d %d %d %d %d %d\n", L, W, p[k][0], p[k][1], p[k][2], p[k][3], i); }}}/* _ _ _|d|c|b||_|_|_||__a__|*/void case5( const Rectangle* ori ){const int numCase = 4; int indicator[][4]={ {0, 1, 2, 3}, {1, 0, 2, 3}, {2, 0, 1, 3}, {3, 0, 1, 2}, };int (*p)[4] = indicator;Rectangle r[4];int i,k, L,W;for( k=0; k<numCase; k++){for( i=0; i<16; i++){L=W=0;setConbination( r, ori, i);L = Max( r[p[k][0]].a, r[p[k][1]].a + r[ p[k][2]].a + r[ p[k][3]].a );W = r[p[k][0]].b + Max( r[p[k][1]].b, Max( r[p[k][2]].b, r[p[k][3]].b ) );setSolution( L, W );}}}void show( FILE* STREAM ){fprintf( STREAM, "%d\n%d %d\n", minArea, solution[0].a, solution[0].b );int i;for( i=1; i<count; i++){if ( solution[i].a * solution[i].b != minArea ) break;if ( solution[i].a == solution[i-1].a) continue;fprintf( STREAM, "%d %d\n", solution[i].a, solution[i].b );}} int cmp( const void* x, const void* y){const Rectangle *xx = x, *yy=y;int s=xx->a * xx->b,t=yy->a * yy->b;if( s>t )return 1;else if ( s<t )return -1;elsereturn (xx->a - yy->a); //面积相同,长越小越好 }int main(){FILE *fin, *fout;fin = fopen("packrec.in", "r");fout = fopen("packrec.out", "w");Rectangle rec[4];int i=0;while( i!=4 ){if( fscanf( fin, "%d %d", &rec[i].a, &rec[i].b )!=2 ){perror(" fscanf error\n");exit(0);}i++; } case1(rec);case2(rec);case3(rec);case4(rec);case5(rec);qsort( solution, count, sizeof(solution[0]), cmp);show( fout );show( stdout );fclose(fin);fclose(fout);return 0;}
代码写得很渣的感觉,caseX() 函数的重复代码很多,r[ indicator[][] ]的使用也很难看。 注释也是一个问题,都不知道怎么才说的清楚。表达能力的问题...哎。
调试还算简单,注释掉4个caseX调用,就能逐个排查了。 田字的重叠处理当时觉得真心麻烦,可是写出来好像也没几行代码。。。
自己折腾的测试用例
3 5
1 3
2 4
2 5
//田字40
3 4
2 5
3 3
2 4
//田字中空排列 40
17 11
16 20
4 6
13 19
//田字 840
5 5
1 7
2 6
2 2
//54,
5 5
1 7
2 6
1 2
//49
- USACO Section 1.4 packrec
- USACO Section 1.4 packrec - 不是太好写的搜索水题
- USACO 1.4 packrec
- USACO 1.4 Packing Rectangles (packrec)
- usaco 1.4 packrec 2008.5.6
- usaco packrec
- USACO packrec
- usaco——packrec
- USACO Section 1.4 题解
- USACO Section 1.4
- USACO Section 1.4
- [USACO Training] Section 1.4
- USACO Section 1.4 Packing Rectangles
- USACO Section 1.4 The Clocks
- USACO Section 1.4 Packing Rectangles
- USACO Section 1.4 Arithmetic Progressions
- 等差数列 [USACO Training Section 1.4]
- USACO-Section 1.4 Arithmetic Progressions
- hdu 4632——Palindrome subsequence
- Protocol Block成员变量补充
- gdb断点的条件调试
- linux命令集:按从大到小的顺序显示当前目录下的各子目录和文件大 小
- Oracle中select SEQ_YX.nextval from dual是什么意思
- USACO Section 1.4 packrec
- Android Activity生命周期
- Winform实现简单的图片切换
- Oracle profile使用
- Address already in use: JVM_Bind解决办法
- F7的值改变事件
- 为omap3530使用BusyBox构建linux文件系统及添加telnet服务
- Matlab 读写入文件txt
- Pascal's Triangle