//毕竟我不是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. 【tarjan】BZOJ 1051:受欢迎的牛

    1051: [HAOI2006]受欢迎的牛 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3134  Solved: 1642[Submit][Sta ...

  2. 【POJ】【1067】取石子游戏

    博弈论 这个是博弈游戏中的Wythoff博弈: 以下为我的代码: //POJ 1067 #include<cmath> #include<cstdio> #include< ...

  3. [转载]C#获取本机IPv4地址

    C#获取本机IP地址在C#1.0之后都使用下面的这种形式: IPHostEntry ipe = Dns.GetHostEntry(Dns.GetHostName()); IPAddress ipa=i ...

  4. 关于struts2如何去掉默认的后缀(.action)

    struts2是可以配置默认的后缀名的,如http://localhost:8080/test.action,这个是默认的,但是也可以通过配置去修改这个.action为别的. 这里是通过一个常量配置改 ...

  5. 利用vim阅读源代码一个好用的工具

    阅读源代码时常常遇到找变量,函数定义的问题.vim为我们提供了一个好用的工具,ctags. 安装 ctags. 在 libvirt的源代码根目录运行 ctags -R . vim -t virConn ...

  6. HDU 1829 A Bug's Life(种类并查集)

    思路:见代码吧. #include <stdio.h> #include <string.h> #include <set> #include <vector ...

  7. 黑马程序员-C#学习笔记(二)

    ---------------------- ASP.Net+Android+IOS开发..Net培训.期待与您交流! ---------------------- - C# 学习笔记 一.变量与表达 ...

  8. 手把手VirtualBox虚拟机下安装rhel6.4 linux 64位系统详细文档

    下面演示安装的是在VirtualBox里安装rhel 6.4 linux 64位系统. 一.VirtualBOX 版本. 二.虚拟机的配置. 1.现在开始演示安装,一起从零开始.点击“新建”,创建新的 ...

  9. 单例模式与Android

    http://blog.csdn.net/ljianhui/article/details/29275655 多线程下的单例模式是不安全的 Android中的单例模式 Android中存在着大量的单例 ...

  10. 69. Sqrt(x)

    题目: Implement int sqrt(int x). Compute and return the square root of x. 链接:   http://leetcode.com/pr ...