【USACO】packrec
这道题卡了很久,开始没读清楚题,没看到题目中给的6个组合是仅可能的组合,一直自己想有多少种组合方式。后来才发现,于是就想到写遍历。我想的是,这六种情况下,每个位置摆哪个矩形是不确定的,于是可以对方块的排列方法遍历,对每个方块是横放还是竖放遍历。写了一个9层的循环,效率很低,有非常多的重复。不过通过了。
#include <stdio.h> #include <stdlib.h> #include <math.h> typedef struct { int x; int y; }RECTANGLE; typedef struct { RECTANGLE r[2]; }RECRotate; int cmp(const void *a1, const void *a2) { return ((RECTANGLE *)a1)->x - ((RECTANGLE *)a2)->x; } int max(int a, int b) { return a > b ? a : b; } int min(int a, int b) { return a < b ? a : b; } int assem(int c, RECTANGLE r1, RECTANGLE r2, RECTANGLE r3, RECTANGLE r4, RECTANGLE *out) { switch(c) { case 1: out->x = r1.x + r2.x + r3.x + r4.x; out->y = max(r4.y, max(r3.y, max(r1.y, r2.y))); break; case 2: out->x = max(r4.y, r1.x + r2.x + r3.x); out->y = max(r3.y, max(r1.y, r2.y)) + r4.x; break; case 3: out->x = max(r1.x + r2.x + r3.x, r3.x + r4.y); out->y = max(r1.y + r4.x, max(r3.y, r2.y + r4.x)); break; case 4: //basic 4 and basic 5 have the same area out->x = max(r2.x, r3.x) + r1.x +r4.x; out->y = max(r2.y + r3.y, max(r1.y, r4.y)); break; case 5: if(r3.y >= r4.y) { out->x = max(r2.y + r3.x, max(r3.x + r4.x, r1.x + r2.y)); out->y = max(r1.y + r3.y, r2.x + r4.y); } break; default: break; } return 0; } int isfirst(RECTANGLE *outr, int num, RECTANGLE tmp) //判断答案是否第一次出现 因为计算有冗余 可能有相同答案出现多次 { int i; for(i = 0; i < num; i++) { if(tmp.x == outr[i].x || tmp.y == outr[i].x) { return 0; } } return 1; } int main() { FILE *in, *out; RECRotate recin[4]; //原始输入矩阵 RECTANGLE outr[10]; int i, j[5], k[4]; in = fopen("packrec.in", "r"); out = fopen("packrec.out", "w"); for(i = 0; i < 4; i++) { fscanf(in, "%d %d", &recin[i].r[0].x, &recin[i].r[0].y); recin[i].r[1].x = recin[i].r[0].y; recin[i].r[1].y = recin[i].r[0].x; } RECTANGLE R1; RECTANGLE R2; RECTANGLE R3; RECTANGLE R4; RECTANGLE OUTTMP; int minarea = 9999999; int outnum = 0; for(j[1] = 0; j[1] < 4; j[1]++) //对每个位置采用第几个方块遍历 { for(j[2] = 0; j[2] < 4; j[2]++) { if(j[2] == j[1]) continue; for(j[3] = 0; j[3] < 4; j[3]++) { if(j[3] == j[2] || j[3] == j[1]) continue; for(j[4] = 0; j[4] < 4; j[4]++) { if(j[4] == j[3] || j[4] == j[2] || j[4] == j[1]) continue; for(k[0] = 0; k[0] < 2; k[0]++) { for(k[1] = 0; k[1] < 2; k[1]++) //对每个方块采用横放竖放遍历 { for(k[2] = 0; k[2] < 2; k[2]++) { for(k[3] = 0; k[3] < 2; k[3]++) { R1 = recin[j[1]].r[k[0]]; R2 = recin[j[2]].r[k[1]]; R3 = recin[j[3]].r[k[2]]; R4 = recin[j[4]].r[k[3]]; for(i = 1; i < 6; i++) //对6种情况遍历 { assem(i, R1, R2, R3, R4, &OUTTMP); if(OUTTMP.x * OUTTMP.y < minarea) { minarea = OUTTMP.x * OUTTMP.y; outnum = 1; outr[outnum - 1] = OUTTMP; } else if(OUTTMP.x * OUTTMP.y == minarea && isfirst(outr, outnum, OUTTMP)) { outnum++; outr[outnum - 1] = OUTTMP; } } } } } } } } } } for(i = 0; i < outnum; i++) //令短边长在前 { if(outr[i].x > outr[i].y) { int tmp = outr[i].x; outr[i].x = outr[i].y; outr[i].y = tmp; } } qsort(outr, outnum, sizeof(outr[0]), cmp); //按照短边长从小到大输出 fprintf(out, "%d\n", minarea); for(i = 0; i < outnum; i++) { fprintf(out, "%d %d\n", outr[i].x, outr[i].y); } return 0; }