`
zqynux
  • 浏览: 36804 次
  • 性别: Icon_minigender_1
  • 来自: 湖南
社区版块
存档分类
最新评论

Packing Rectangles 铺放矩形块 (IOI 95)

阅读更多
Packing Rectangles 铺放矩形块 (IOI 95)

在网上看了挺多解释这一题的文章,总感觉没看大懂,所以自己写一篇文章吧。希望能够帮助大家理解一下这一题。题目如下:

http://www.nocow.cn/index.php/Translate:USACO/packrec



开始拿到题目确实没怎么看懂,网上也有很多人说它是个水题,我倒感觉不以为然,我看了一些网上的人写的代码,说它是水题的人都是怎么写的。整个程序框架就是第一种情况循环+判断,第二种情况循环+判断,…………(以此类推)

接下来我来说下我的做法,(我的语言表达能力却是不强,可能会看不懂,所以如果你看不懂分析的话直接看代码的注释吧。)

对于任何一个矩形都有两种数据:长和宽,然而在这个程序中这方面是最难处理的也就是如何交换长和宽,也就是说在同一个矩形会拥有两种状况——横着摆,竖着摆。我就用srch1这个函数来实现所有矩形长和宽的交换。

接下来就是位置的问题,该把哪个矩形放在哪里面积最小呢呢?当然,这个是看不出来的。所以也需要进行反复的迭代,我用srch2来实现的。

最后再就是判断6种情况(其实只有五种,4和5是一样的)。

(不知道描述清楚没有。)接下来我把代码进行一下简单的注释吧。

/*
LANG: C
ID: zqy11001
PROG: packrec
QQ: 328400264
*/
#include <stdio.h>
 
#define swap(a, b) do{\
         a ^= b;\
         b ^= a;\
         a ^= b;\
}while(0);
#define max(a, b) ((a)>(b)?(a):(b))
 
int m;
int ans[300], s1[4], s2[4];
int a[4], b[4];
 
void update(int x, int y)
{
         if(x * y < m){
                   m = x * y;
                   memset(ans, 0, sizeof(ans));
         }
         if(x * y == m){
                   ans[x] = ans[y] = 1;
         }
}
 
int box(int x1, int y1, int x2, int y2, int x3, int y3,
                   int x4, int y4)
{
         int x, y;
         x = x1 + x2 + x3 + x4;
         y = max(max(y1, y2), max(y3, y4));
         update(x, y);
 
         x = max(x1, x2 + x3 + x4);
         y = y1 + max(y2, max(y3, y4));
         update(x, y);
 
         x = x1 + max(x2, x3 + x4);
         y = max(y1, y2 + max(y3, y4));
         update(x, y);
 
         x = x1 + x4 + max(x2, x3);
         y = max(y1, max(y4, y2 + y3));
         update(x, y);
 
         x = max(max(x1 + x2, x3 + x4), x1 + x4);
         y = max(max(y1 + y3, y2 + y4), y2 + y3);
         update(x, y);
}
 
void srch2(int n)
{
         int i;
         if(n == 4){
                   box(a[s2[0]], b[s2[0]], a[s2[1]], b[s2[1]],
                                   a[s2[2]], b[s2[2]], a[s2[3]], b[s23]]);
         }else{
                   for(i = 0; i < 4; i++){
                            if(!s1[i]){
                                     s2[n] = i;
                                     s1[i] = 1;
                                     srch2(n + 1);
                                     s1[i] = 0;
                            }
                   }
         }
}
 
void srch1(int n)
{
         if(n == 4){
                   memset(s1, 0, sizeof(s1));
                   srch2(0);
         }else{
                   srch1(n + 1);
                   swap(a[n], b[n]);
                   srch1(n + 1);
                   swap(a[n], b[n]);
         }
}
 
int main(void)
{
         int i, j;
         freopen("packrec.in", "r", stdin);
         freopen("packrec.out", "w", stdout);
         for(i = 0; i < 4; i++){
                   scanf("%d%d", &a[i], &b[i]);
         }
         m = 10000;
         srch1(0);
         j = sqrt(m);
         printf("%d\n", m);
         for(i = 1; i <= j; i++){
                   if(ans[i]){
                            printf("%d %d\n", i, m / i);
                   }
         }
         return 0;
}

接下来我对函数一个个进行一下简单的分析吧。
首先

引用
#define swap(a, b) do{\
         a ^= b;\
         b ^= a;\
         a ^= b;\
}while(0);
#define max(a, b) ((a)>(b)?(a):(b))


这两个宏是很简单的,swap把a和b交换一下位置,max是求两者最大值。

Tip: 对于swap的话,三个异或就能完成问题,这个可能部分读者看不懂,本文是对这个题目的分析,如果看不大懂的话就改成

引用

#define swap(a, b) do{\
         int t;\
         t = a;
         a = b;
         b = t;
}while(0);




然后再是对变量进行分析,ans是存储结果用的,因为题目要求输出的时候要从小到大,所以使用ans来存储,输出的时候判断如果当前的值是1的话就输出,不然的话就继续寻找下一个。m是面积最大值。a和b是存储长和宽的。s1和s2到要用的时候再介绍吧。

box函数就是对六种情况算面积,再用update函数来更新m和ans两个全局变量,如果这一种情况求出的面积和m的一样,那么就用这个面积的长和宽来更新ans。如果面积比m还要小,那么将m设置成这个面积,将ans置空,再用长和宽来更新ans。

接下来先介绍srch1吧。

引用
void srch1(int n)
{
         if(n == 4){
                   memset(s1, 0, sizeof(s1));
                   srch2(0);
         }else{
                   srch1(n + 1);
                   swap(a[n], b[n]);
                   srch1(n + 1);
                   swap(a[n], b[n]);
         }
}
这个n表示当前这种方案的下标。

这个函数可以这么理解,

先直接调用一次srch1(n + 1);就是枚举四个矩形用a做底,b做高的所有情况,接下来在把第n个矩形的长和高调一下位置再srch1(n + 1).因为刚刚把第n个矩形的长和高换了位置,所以还要把它换回来。

然后当n==4的时候,四个矩形都递归完了,就该做些什么了,做些什么呢?

继续看就知道了。

调用srch2之前为什么要把s1置0呢`?

看看srch2是怎么写的`
引用

void srch2(int n)
{
         int i;
         if(n == 4){
                   box(a[s2[0]], b[s2[0]], a[s2[1]], b[s2[1]],
                                   a[s2[2]], b[s2[2]], a[s2[3]], b[s2[3]]);
         }else{
                   for(i = 0; i < 4; i++){
                            if(!s1[i]){
                                     s2[n] = i;
                                     s1[i] = 1;
                                     srch2(n + 1);
                                     s1[i] = 0;
                            }
                   }
         }
}

可能有读者要说了,这跟srch1有点像啊.. 好吧, 我承认, 我摘抄了srch1的部分代码,但是srch2的功能未必也是将第n个矩形的长和高交换?肯定不是啦。

当n==4的时候就是真正的进行判断了,所以理解else是重点.本函数的功能是,对四个矩形的长和高调用box的时候的顺序进行反复的交换。所以else里面是一个for循环,这里s1和s2就是用来判断重复的情况的,s1标志当前这个矩形是否已经被使用了?s2标志当前这个矩形的实质是什么?

汗,,自己都没看懂这段话,再理一下。。

s2[i]的意思是第i个矩形实际上是第几个矩形。因为四个矩形要反复的进行交换,所以s2就是交换的中间变量。那有人会问了。

引用
                            if(!s1[i]){
                                     s2[n] = i;
                                     s1[i] = 1;
                                     srch2(n + 1);
                                     s1[i] = 0;
                            }


这段是什么意思呢? 呵呵,你们想想,如果直接

s2[n] = i;

srch2(n + 1);

的话那会有这种可能s2[0] == 0, s2[1] == 0, s2[2]==0, 也就是说在调用box的时候这些矩形分身了。s1在这里就是用来防止这种情况,s1用来标志这一个矩形是否被别的s2给使用了,如果使用了那s1就会是1,那么循环只好继续。



整个程序大概分析完了。。

如果还没看懂,那不是你蠢了,是我没写清楚吧。

总之如果还有问题,联系我的QQ:328400264
0
0
分享到:
评论

相关推荐

    matlab开发-rectangles

    `rectangles.m`可能是一个函数,它包含了绘制单个或多个矩形的基本逻辑。这可能包括设置矩形的位置、大小、颜色和线型等属性。MATLAB中的`rectangle`函数是用于绘制矩形的主要工具,它可以接受各种参数,例如`'...

    convex-rect-pack:启发式二维矩形打包算法

    项目实现启发式二维矩形打包算法### Used for:在凸凹容器中包装尽可能多的矩形基于论文中描述的想法: "A heuristic approach for packing rectangles in convex regions" by Andrea Cassioli, Marco Locatelli" ...

    On dividing rectangles into rectangles

    总的来说,《On dividing rectangles into rectangles》这篇论文通过引入一种新颖的递归方法,解决了矩形分割问题,并提供了一系列实用的计算工具。这种方法不仅能够计算任意大小矩形的分割方案数量,而且通过构造...

    Word VBA中Rectangles.txt

    Word VBA中通过Rectangles选中页眉、页脚、正文(包含整页内容、整行、字符)

    运用模拟退火算法解决简单矩形布局问题-python_rectangles-ranged-problem.zip

    运用模拟退火算法解决简单矩形布局问题-python_rectangles-ranged-problem

    C# 显示图片并且可以缩放和描绘矩形

    在本场景中,我们关注的是如何在WinForm窗体中显示图片并提供缩放及绘图功能,特别是描绘矩形。这个任务可以通过利用PictureBox控件来实现。PictureBox控件允许我们加载图像并在窗体中显示。 首先,我们需要在...

    在VS2008环境下,用C#在窗体上画出多个矩形框,可用于图像的选择

    在使用Visual Studio 2008 (VS2008) 进行C#编程时,我们可以创建一个Windows Forms应用程序来实现用户界面,允许在窗体上绘制多个矩形框。这种功能通常用于图像处理或编辑应用,比如选择、裁剪或标注图像中的特定...

    rectangles:有效地绘制一堆具有曲率和旋转的矩形。-matlab开发

    Matthew Eicholtz编写的一个非常有用的函数“ RECTANGLES”通过将多个矩形绘制为单个面片来解决了我的问题。 https://www.mathworks.com/matlabcentral/fileexchange/59243-rectangles 但是,当我想向矩形添加曲率...

    Direct_采样_direct优化策略_

    DIRECT算法的核心思想是将搜索空间划分为多个小的 hyper-rectangles(超矩形),每个超矩形代表一个潜在的解区域。在每次迭代中,算法会选择具有最大可能包含全局最优解的超矩形进行细化,以此逐步缩小全局最优解的...

    python3+openCV 获取图片中文本区域的最小外接矩形实例

    ### Python3 + OpenCV 获取图片中文本区域的最小外接矩形 #### 一、引言 在图像处理领域,经常需要对图像中的文本区域进行定位。这些应用场景包括但不限于文档扫描、车牌识别、屏幕文字抓取等。OpenCV 是一个强大的...

    nested-rectangles-js:在Javascript中绘制n个具有不同颜色(数组)的嵌套矩形

    "nested-rectangles-js"项目就是这样一个示例,它专注于利用JS来绘制嵌套的矩形,每个矩形可能拥有不同的颜色。这通常是通过DOM操作或者利用像HTML5 Canvas这样的绘图API来实现的。 在给定的场景中,`addRect(15)`...

    movable-rectangles:使用canvas实现可移动的矩形

    "movable-rectangles"项目正是基于此技术实现了一个功能,让用户可以交互地移动Canvas上的矩形。接下来,我们将深入探讨如何使用JavaScript和HTML5 Canvas API来创建和操作这些可移动的矩形。 首先,我们需要在HTML...

    Python-Find_Rectangles:查找比背景暗的纯色矩形

    在本项目"Python-Find_Rectangles"中,我们的目标是使用Python编程语言来检测并识别出图像中的比背景暗的纯色矩形。这通常在处理图像分析、计算机视觉或机器学习任务时非常有用,例如在自动驾驶、机器人导航或者监控...

    画图软件用C#做的可以画圆画矩形填充圆形还可以随机画矩形等等

    在本文中,我们将深入探讨如何使用C#编程语言创建一个简单的画图软件,该软件能够绘制圆、矩形并填充圆形,以及实现随机绘制矩形的功能。C#是一种广泛用于开发Windows应用程序的强大语言,尤其适合构建图形用户界面...

    安卓Android源码——(矩形碰撞).zip

    本资源“安卓Android源码——(矩形碰撞).zip”提供了一个关于矩形碰撞检测的示例代码,这将帮助开发者更好地理解和实现这个功能。 矩形碰撞检测通常用于检查两个矩形是否在空间上重叠。在2D游戏中,矩形是最常见的...

    完美矩形(java代码).docx

    ### 完美矩形判定算法解析 #### 一、问题背景与定义 在计算机图形学领域,有时我们需要处理多个矩形区域,其中一个常见的问题是:如何判断这些矩形能否精确地覆盖一个更大的矩形区域,而不会有任何重叠或遗漏的...

    All_Rectangles:完美的正方形或不相等的矩形,不用担心,java程序可在大Rectangle中查找矩形的数量

    标题"所有矩形:完美的正方形或不相等的矩形,不用担心,Java程序可在大Rectangle中查找矩形的数量"暗示我们讨论的是一个Java程序,它能够在一个大的矩形区域内寻找并计数所有可能的子矩形,无论这些矩形是完美的...

    zoj 1179 Finding Rectangles.md

    zoj 1179 Finding Rectangles.md

    行业教育软件-学习软件-Triangles Rectangles Solver 1.2 英文版.zip

    《Triangles Rectangles Solver 1.2 英文版:行业教育软件在几何学习中的应用》 在当今数字化的时代,教育软件已经成为辅助学习的重要工具。"Triangles Rectangles Solver 1.2 英文版"就是这样一款专为行业教育设计...

    一幅图片中画两个矩形

    在OpenCV库中,我们可以利用其丰富的图像处理功能来实现在一个图片上绘制多个矩形。OpenCV是一个跨平台的计算机视觉库,它包含了各种用于图像处理、计算机视觉以及机器学习的函数。本教程将深入讲解如何使用OpenCV在...

Global site tag (gtag.js) - Google Analytics