USACO1.4.1 Packing Rectangles
//毕竟我不是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的更多相关文章
- USACO 6.2 Packing Rectangles
Packing RectanglesIOI 95 The six basic layouts of four rectangles Four rectangles are given. Find th ...
- Section 1.4 Packing Rectangles
本来是USACO Training的1.4.1的,但是介于今早过了食物链想起了这道题实在是太怨念了,翻出自己写的AC程序居然有5KB!! 思路很简单,枚举,而且就图中的六种情况.但是第六种变化状况太多 ...
- [vijos P1531] 食物链
做出的第一道NOI题目?(噗,还是看题解才会的…按某篇解题说的,这题就比我年轻四岁…T T 做的第一道IOI题目是USACO上的Packing Rectangles...这题比我还老!)对我等弱渣来说 ...
- USACO chapter1
几天时间就把USACO chapter1重新做了一遍,发现了自己以前许多的不足.蒽,现在的程序明显比以前干净很多,而且效率也提高了许多.继续努力吧,好好的提高自己.这一章主要还是基本功的训练,没多少的 ...
- USACO1.5Superprime Rid[附带关于素数算法时间测试]
题目描述 农民约翰的母牛总是产生最好的肋骨.你能通过农民约翰和美国农业部标记在每根肋骨上的数字认出它们.农民约翰确定他卖给买方的是真正的质数肋骨,是因为从右边开始切下肋骨,每次还剩下的肋骨上的数字都组 ...
- USACO1.1Broken Necklace[环状DP作死]
题目描述 你有一条由N个红色的,白色的,或蓝色的珠子组成的项链(3<=N<=350),珠子是随意安排的. 这里是 n=29 的二个例子: 第一和第二个珠子在图片中已经被作记号. 图片 A ...
- poj-1314 Finding Rectangles
题目地址: http://poj.org/problem?id=1314 题意: 给出一串的点,有些点可以构成正方形,请按照字符排序输出. 因为这道题的用处很大, 最近接触的cv 中的Rectangl ...
- Bin Packing
Bin Packing 题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=85904#problem/F 题目: A set of ...
- [ACM_暴力][ACM_几何] ZOJ 1426 Counting Rectangles (水平竖直线段组成的矩形个数,暴力)
Description We are given a figure consisting of only horizontal and vertical line segments. Our goal ...
随机推荐
- setDepthStencilState
cgfx->hlsl StencilFunc={always,1,0xff}->setDepthStencilState(DepthState,0) StencilFunc={always ...
- 【WCF--初入江湖】10 序列化和传输大型数据流
10 序列化和传输大型数据流 1.前言 理解WCF的序列化形式 掌握DataContractSerializer序列化对象 比较性能 比较xmlSerializer序列化对象 大数据量传输设置 修 ...
- Castle 开发系统文章
转: http://www.cnblogs.com/Jebel/archive/2008/06/24/1228766.html
- linux源代码阅读笔记 linux文件系统(三)
当系统申请一个新的inode时.系统并不会对磁盘进行读写.它会在存储在内存的inode表(inode_table)中寻找一个空闲的位置. 如果找到了,直接返回该inode.否则要等待一个空闲的位置. ...
- DataRow.RowState 属性
RowState 的值取决于两个因素:已对该行执行的操作的类型,以及是否已对 DataRow 调用了 AcceptChanges. private void DemonstrateRowState() ...
- hdu 1271 整数对
看了别人的解题报告a了, 大致思路就是 A=a+b*10^k+c*10^(k+1) B=a+c*10^k (在A中取出一位数后) N=A+B=2*a+b*10^k+11*c*10^k 这样就好做了,再 ...
- javascript 在一个函数参数中包含另一个函数的引用
javascript函数的参数包含另一个函数的情形: <script> //b函数的参数func为另一个函数 function b(a, func) { alert(a); //调用参数 ...
- codeforces div.1 A
A. Efim and Strange Grade time limit per test 1 second memory limit per test 256 megabytes input sta ...
- 规范化ProjectEuler
Euler Level3 规范化程序: 包名:LevelX,X是等级 每题程序名:PE0xx.java,PE0xx.py 程序有必要的注释,不同方法运行结果也在程序中 规范化博文: 名字:Projec ...
- 4、JPA table主键生成策略(在JPA中table策略是首推!!!)
用 table 来生成主键详解 它是在不影响性能情况下,通用性最强的 JPA 主键生成器.这种方法生成主键的策略可以适用于任何数据库,不必担心不同数据库不兼容造成的问题. initialValue不起 ...