//毕竟我不是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】【1693】Eat The Trees

    插头DP 插头dp模板题…… 这题比CDQ论文上的例题还要简单……因为不用区分左右插头(这题可以多回路,并不是一条哈密尔顿路) 硬枚举当前位置的状态就好了>_< 题解:http://blo ...

  2. git如何ignore

    今天新建了一个项目传到git上,但是每次编译都会有一些无用的文件生成,于是就编写了ignore.但是发现无用.因为你的文件已经上传到服务器了,再编写ignore就无用了,ignore的适用是文件没上传 ...

  3. 控制DIV属性——实现盒子长、宽、背景等变化

    写在最前面:Demo的源起来自于http://js.fgm.cc/learn/,但是实现部分都是经过自己思考和优化的,有时会借助别人的图片,然而“窃喜”.如无特殊说明,demo都是经过ie6.ie7等 ...

  4. 项目中的Libevent(多线程)

    多线程版Libevent //保存线程的结构体 struct LibeventThread { LibEvtServer* that; //用作传参 std::shared_ptr<std::t ...

  5. [nowCoder] 子数组最大乘积

    给定一个double类型的数组arr,其中的元素可正可负可0,返回子数组累乘的最大乘积.例如arr=[-2.5,4,0,3,0.5,8,-1],子数组[3,0.5,8]累乘可以获得最大的乘积12,所以 ...

  6. hdu 4869

    一个机智题,可惜比赛的时候没有机智出来 #include<cstdio> #include<cstring> #include<cmath> #include< ...

  7. 表中相同数据的sql语句

    1.查找表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断select * from peoplewhere peopleId in (select   peopleId from  ...

  8. django如何用orm增加manytomany关系字段(自定义表名)

    不自定义表名的,网上有现成的,但如果自定义之后,则要变通一下了. app_insert = App.objects.get(name=app_name) site_insert = Site.obje ...

  9. hdu 1288 Hat's Tea

    这个要慢慢理解…… ;}

  10. ASP.NET 免费开源控件

    AspNetPager分页控件(当前版本:7.5.1) AspNetPager分页控件是应用于ASP.NET WebForm网站或应用程序中的自定义分页控件,支持默认的回发(Postback)分页和U ...