//毕竟我不是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. Matlab中@与函数调用

    function m f=@(x) x^2; y(f,3); function y(f,x) disp(num2str(f(x))); end end 函数调用另一个函数的时候,把另一个函数名作为参数 ...

  2. 【转载】CCombobox使用大全

    一.如何添加/删除Combo Box内容 1. 在Combo Box控件属性的Data标签里面添加,一行表示Combo Box下拉列表中的一行.换行用ctrl+回车. 2. 在程序初始化时动态添加 如 ...

  3. struts.properties配置详解(转)

    Struts 2框架有两个核心配置文件,其中struts.xml文件主要负责管理应用中的Action映射,以及该Action包含的Result定义等.除此之 外,Struts 2框架还包含     s ...

  4. Linux操作系统下软件的安装方法大全

    一.rpm包安装方式步骤: 1.找到相应的软件包,比如soft.version.rpm,下载到本机某个目录: 2.打开一个终端,su -成root用户: 3.cd soft.version.rpm所在 ...

  5. 在smarty模板中取不到Cookie的值解决方案

    在原生PHP中我们用:setcookie()来设置Cookie变量,用$_COOKIE这个全局变量来读取Cookie.例如 if(!isset($_COOKIE['user'])) { setcook ...

  6. codeforces 397B

    #include <cstdio> #include <cstdlib> #include <cmath> #include <map> #includ ...

  7. Appium绑定

    锁定 锁定屏幕 # python driver.lock(5) 将 app 置于后台 把当前应用放到后台去 # python driver.background_app(5) 收起键盘 收起键盘 # ...

  8. hadoop倒排索引

    1.前言 学习hadoop的童鞋,倒排索引这个算法还是挺重要的.这是以后展开工作的基础.首先,我们来认识下什么是倒拍索引: 倒排索引简单地就是:根据单词,返回它在哪个文件中出现过,而且频率是多少的结果 ...

  9. JS创建对象

    本人常用的创建对象的方式,仅供参考,欢迎吐槽,谢谢! 创建对象1.对象字面量,即使用大括号,如下: (function(){ var obj = { id: 1, desc: '创建对象测试开始啦!' ...

  10. [wikioi]线段树练习 2

    http://codevs.cn/problem/1081/ #include <vector> #include <iostream> #include <string ...