//毕竟我不是dd牛,USACO的题解也不可能一句话带过的……

题目链接:http://cerberus.delos.com:790/usacoprob2?a=pWvHFwGsTb2&S=packrec

题目大意就是给定四个矩形,让你找到一个面积最小的矩形使得这四个矩形都能放进去(不能重叠),要求输出最小矩形的面积以及长宽(可能有多个矩形都具有最小面积)。

既然题目里已经给了六种模型(第4种和第5种其实是一样的),那就一种一种写吧。

没有什么特别的算法,就是搜索。每个矩形都可以横放或者竖放,所以用一个dir[4]数组表示4个矩形的放置方式:0表示竖放,即较小边在下;1表示横放,即较大边在下。

为了方便,我还把“找到新矩形并判断面积是否最小并记录其边长”的功能写成了一个函数newans(x, y),具体代码见下:

void newans(int x, int y) {
if (x*y <= mina) {
if (x*y < mina){
mina = x*y;
memset(minx, , sizeof(minx));
}
int v = min(x, mina/x);
if (!minx[mina/v]) {
minx[v] = ;
}
}
}

解释一下这种记录结果的方式:

x,y自然是新生成的矩形的长宽;mina即最小面积(min area);minx[201]记录了最小矩形的较短边(或者说宽),即当minx[w]==1时,说明有一个最小矩形的宽为w。如果生成了更小的矩形,那么重置minx,更新mina。而且题目要求先输出矩形的较短边,再输出较长边,那么这里为了省事,只记录较短边。(即如果生成一个5 8的最小矩形,mina=40,minx[5]=1,minx[8]=0。)

然后回溯吧。(接下来这些描述中,宽是指放在下面的那条边,而不是指较小边)

Case 1:

不用说,简单回溯就好了。有点全排列的感觉:在dir数组每个位置上放1或者0。当然也可以用二进制数的方法:从0枚举到15,用位运算取出每位上的数。

Case 2:

感觉自己用了很奇葩的方法:在主函数里用循环来枚举放在下面的矩形,然后再回溯搜索dir的可能情况。可能解释不太清楚,具体可以看代码。那么这个新生成的矩形的长取上面三个矩形的宽之和与下面这个矩形的长的较大者,宽取上面三个矩形的长的最大值+下面这个矩形的宽。

Case3/4/5:

都类似于Case 2,只是需要确定的矩形个数变成了两个。

Case 6:

最让人头疼的一种情况,当初也是因为看到这种情况才放弃这道题的(所以一直拖了半年)。冷静分析之后,按照我之前处理其他情况的方法,可以先确定四个矩形分别在哪个位置,回溯搜索dir。只是关于重叠的问题需要大量的判断。比如我遇到左上矩形的宽大于左下矩形的宽时,就直接放弃这种情况(不用担心遗漏,因为一定有一种情况和它是对称的,即这种情况下的左上矩形成了那种情况的右上矩形)。具体的判断比较复杂,直接看代码吧。

提交了11次才通过。囧。第1次提交的时候,第1组数据(样例)都没有通过,这让我十分苦恼啊,在自己的电脑上完全没问题啊。然后,看了下USACO的FAQ,决定用cerr把中间结果输出来,于是我就在USACO的测评机上调试自己的代码……好吧,几次调试之后,发现是有个变量忘了初始化了,而自己的电脑上估计已经初始化成0了。所以说编译器如果太智能也不行,这种低级的错误都没法让写程序的人发现。后来的几次提交发现了Case 6的处理还有一些问题,于是不断修改。然后AC。

总共用了将近4小时吧,从8点一直做到11点多才AC。200+行,总代码长度4K+(不得不说是我写得太复杂了),最后0ms通过。爽。

代码如下:

#include <iostream>
#include <fstream>
#include <cstring>
#include <algorithm> #define cin fin
#define cout fout #define INF 50000 using namespace std; ifstream fin("packrec.in");
ofstream fout("packrec.out"); int rect[][]; // 0:x 1:y x<=y
int minx[], mina = INF;
int dir[]; // 0:vertical 1:horizontal void newans(int x, int y) {
if (x*y <= mina) {
if (x*y < mina){
mina = x*y;
memset(minx, , sizeof(minx));
}
int v = min(x, mina/x);
if (!minx[mina/v]) {
minx[v] = ;
}
}
} void pack1(int step) {
if (step == ) {
int cy = , cx = , i, x[], y[];
for (i=; i<; i++) {
x[i] = rect[i][dir[i]];
y[i] = rect[i][-dir[i]];
if (y[i] > cy) {
cy = y[i];
}
cx += x[i];
}
newans(cx, cy);
}
else {
dir[step] = ;
pack1(step+);
dir[step] = ;
pack1(step+);
}
} void pack2(int btm, int step) {
if (step == ) {
int cy = , cx = , i, x[], y[];
for (i=; i<; i++) {
x[i] = rect[i][dir[i]];
y[i] = rect[i][-dir[i]];
}
for (i=; i<; i++) {
if (i != btm) {
if (y[i] > cy) {
cy = y[i];
}
cx += x[i];
}
}
newans(max(cx, y[btm]), cy+x[btm]);
}
else {
dir[step] = ;
pack2(btm, step+);
dir[step] = ;
pack2(btm, step+);
}
} void pack3(int btm, int rgt, int step) {
if (step == ) {
int cy = , cx = , i, x[], y[];
for (i=; i<; i++) {
x[i] = rect[i][dir[i]];
y[i] = rect[i][-dir[i]];
}
for (i=; i<; i++) {
if (i!=btm && i!=rgt) {
if (y[i] > cy) {
cy = y[i];
}
cx += x[i];
}
}
newans(max(cx, y[btm])+x[rgt], max(cy+x[btm], y[rgt]));
}
else {
dir[step] = ;
pack3(btm, rgt, step+);
dir[step] = ;
pack3(btm, rgt, step+);
}
} int pack4(int top, int btm, int step) {
if (step == ) {
int cy, cx, i, x[], y[];
for (i=; i<; i++) {
x[i] = rect[i][dir[i]];
y[i] = rect[i][-dir[i]];
}
cy = y[top] + y[btm];
cx = max(x[top], x[btm]);
for (i=; i<; i++) {
if (i!=btm && i!=top) {
if (y[i] > cy) {
cy = y[i];
}
cx += x[i];
}
}
newans(cx, cy);
}
else {
dir[step] = ;
pack4(top, btm, step+);
dir[step] = ;
pack4(top, btm, step+);
}
} void pack6(int lft, int rgt, int top, int step) {
if (step == ) {
int cx, cy, i, last, x[], y[];
for (i=; i<; i++) {
x[i] = rect[i][dir[i]];
y[i] = rect[i][-dir[i]];
if (i!=lft && i!=rgt && i!=top) {
last = i;
}
}
if (x[top] > x[lft]) {
return;
}
cx = x[lft] + x[rgt];
cy = y[lft] + y[top];
if (cy > y[rgt]) {
if (y[lft] < y[rgt]) {
if (x[top]+x[last] <= cx) {
cy = max(cy, y[rgt]+y[last]);
}
else {
return;
}
}
else {
if (x[top]+x[last] <= cx) {
cy = max(cy, y[lft]+y[last]);
}
else {
return;
}
}
}
else {
if (x[last]+x[rgt] <= cx) {
cy = max(cy+y[last], y[rgt]);
}
else {
return;
}
}
newans(cx, cy);
}
else {
dir[step] = ;
pack6(lft, rgt, top, step+);
dir[step] = ;
pack6(lft, rgt, top, step+);
}
} int main() {
int i, j, k;
for (i=; i<; i++) {
cin >> rect[i][] >> rect[i][];
if (rect[i][] > rect[i][]) {
rect[i][] += rect[i][];
rect[i][] = rect[i][] - rect[i][];
rect[i][] -= rect[i][];
}
} pack1();
for (i=; i<; i++) {
pack2(i, );
}
for (i=; i<; i++) {
for (j=; j<; j++) {
if (i != j) {
pack3(i, j, );
}
}
}
for (i=; i<; i++) {
for (j=; j<; j++) {
if (i != j) {
pack4(i, j, );
}
}
}
for (i=; i<; i++) {
for (j=; j<; j++) {
for (k=; k<; k++) {
if (i != j && j != k && i != k) {
pack6(i, j, k, );
}
}
}
} cout << mina << endl;
for (i=; i<; i++) {
if (minx[i]) {
cout << i << ' ' << mina/i << endl;
}
} return ;
}

USACO1.4.1 Packing Rectangles的更多相关文章

  1. USACO 6.2 Packing Rectangles

    Packing RectanglesIOI 95 The six basic layouts of four rectangles Four rectangles are given. Find th ...

  2. Section 1.4 Packing Rectangles

    本来是USACO Training的1.4.1的,但是介于今早过了食物链想起了这道题实在是太怨念了,翻出自己写的AC程序居然有5KB!! 思路很简单,枚举,而且就图中的六种情况.但是第六种变化状况太多 ...

  3. [vijos P1531] 食物链

    做出的第一道NOI题目?(噗,还是看题解才会的…按某篇解题说的,这题就比我年轻四岁…T T 做的第一道IOI题目是USACO上的Packing Rectangles...这题比我还老!)对我等弱渣来说 ...

  4. USACO chapter1

    几天时间就把USACO chapter1重新做了一遍,发现了自己以前许多的不足.蒽,现在的程序明显比以前干净很多,而且效率也提高了许多.继续努力吧,好好的提高自己.这一章主要还是基本功的训练,没多少的 ...

  5. USACO1.5Superprime Rid[附带关于素数算法时间测试]

    题目描述 农民约翰的母牛总是产生最好的肋骨.你能通过农民约翰和美国农业部标记在每根肋骨上的数字认出它们.农民约翰确定他卖给买方的是真正的质数肋骨,是因为从右边开始切下肋骨,每次还剩下的肋骨上的数字都组 ...

  6. USACO1.1Broken Necklace[环状DP作死]

    题目描述 你有一条由N个红色的,白色的,或蓝色的珠子组成的项链(3<=N<=350),珠子是随意安排的. 这里是 n=29 的二个例子: 第一和第二个珠子在图片中已经被作记号. 图片 A ...

  7. poj-1314 Finding Rectangles

    题目地址: http://poj.org/problem?id=1314 题意: 给出一串的点,有些点可以构成正方形,请按照字符排序输出. 因为这道题的用处很大, 最近接触的cv 中的Rectangl ...

  8. Bin Packing

    Bin Packing 题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=85904#problem/F 题目: A set of  ...

  9. [ACM_暴力][ACM_几何] ZOJ 1426 Counting Rectangles (水平竖直线段组成的矩形个数,暴力)

    Description We are given a figure consisting of only horizontal and vertical line segments. Our goal ...

随机推荐

  1. 【HDOJ】【1512】Monkey King

    数据结构/可并堆 啊……换换脑子就看了看数据结构……看了一下左偏树和斜堆,鉴于左偏树不像斜堆可能退化就写了个左偏树. 左偏树介绍:http://www.cnblogs.com/crazyac/arti ...

  2. 【POJ】【1704】Georgia and Bob

    组合游戏 Nim游戏的一个变形 题解请看金海峰的博客 以下为引用: 分析:我们把棋子按位置升序排列后,从后往前把他们两两绑定成一对.如果总个数是奇数,就把最前面一个和边界(位置为0)绑定. 在同一对棋 ...

  3. eclipse svn 修改了类名之后提交

    win下面的文件名不区分大小写,所以不能只是把小写类名改成大写. 正确的做法有如下两种:1,先删除类a,提交,此操作会删除服务器上的文件.再添加类A,提交.2,重命名a为aa,提交,此操作会删除服务器 ...

  4. SQL语句备忘

    SELECT beatid,COUNT(d.id) dongnicount FROM `bed_beat_dongni` d INNER JOIN bed_beat b on b.id = d.bea ...

  5. prefix springmvc

    设置了@RequestMapping("/jsp/info.do"),也可以写成"jsp/info.act"不影响 retuen "index&quo ...

  6. POJ 2255 Tree Recovery(根据前序遍历和中序遍历,输出后序遍历)

    题意:给出一颗二叉树的前序遍历和中序遍历的序列,让你输出后序遍历的序列. 思路:见代码,采用递归. #include <iostream> #include <stdio.h> ...

  7. Fragment 与 Activity 通信

    先说说背景知识: (From:http://blog.csdn.net/t12x3456/article/details/8119607) 尽管fragment的实现是独立于activity的,可以被 ...

  8. lintcode 中等题:majority number III主元素III

    题目 主元素 III 给定一个整型数组,找到主元素,它在数组中的出现次数严格大于数组元素个数的1/k. 样例 ,返回 3 注意 数组中只有唯一的主元素 挑战 要求时间复杂度为O(n),空间复杂度为O( ...

  9. 为什么需要用到序列化?为什么HttpSession中对象要序列化

    简单说就是为了保存在内存中的各种对象的状态,并且可以把保存的对象状态再读出来.虽然你可以用你自己的各种各样的方法来保存Object States,但是Java给你提供一种应该比你自己好的保存对象状态的 ...

  10. 基于Struts2框架实现登录案例

    一,准备工作  1)新建web项目,并导入Struts2jar文件和配置web.xml文件. struts2 jar文件 web.xml文件 <?xml version="1.0&qu ...