算法题——立方体的体对角线穿过多少个正方体?

这道题是笔者当年参加竞赛的题目,多年来一直未得其解,久久不能释怀。近日,重新拿起该题细细研究,终于将其解出,著文以记之。

 

问题描述:

长方体长X,宽Y,高Z。X、Y、Z都是正整数。长方体由长1、宽1、高1的正方体堆积而成。那么长方体的体对角线穿过多少个正方体?

 

这个题考量三维空间的想象。近日研究的时候,尝试先考量二维的情况,在求解出二维的情况下,在推广到三维里。下面是二维情况下的问题描述

 

长方形长X,宽Y。X、Y都是正整数。长方形由长1、宽1的正方形组成。那么长方形的对角线穿过多少个正方形?

 

 

以实例说明。长方形长6,宽4。长方形由长1、宽1的正方形组成。那么长方形的对角线穿过多少个正方形?

这个还是比较简单的,直接用图表示即可,如下图所示:

 

 

如上图所示,对角线一共穿过8个正方形(灰色部分)。但是,我们不可能每个问题都画图表示,比如长777,宽581的长方形的解就很难画图表示(数字太大,不容易精确表示)。

仔细看看,这8个正方形实际上把对角线分成了8段。线段的端点是对角线和水平线(或竖直线)的交点。

于是,问题似乎可以转化成

要求穿过多少个正方形,实际上相当于求有多少个线段

要求有多少个线段,实际上相当于求对角线和水平线和垂直线的交点的个数

 

把上图放在平面直角坐标系中,左下角坐标为(0,0),右上角坐标为(6,4)

则对角线的直线方程为

 

 

和我们一般想象中的直线方程不太一样。没关系,首先这个是正确的直线方程,其次是为了和后面的三维中的直线方程的表现形式统一。

我们把对角线和水平线(或竖直线)的交点在图上标示出来(为了后文的描述方便,我用不同颜色标示点)

 

左下角的起点用灰色标示,红色的点标示对角线和竖直线的交点(交点的横坐标是整数),绿色的点标示对角线和水平线的交点(交点的纵坐标是整数)

起点不算,则穿过的方块数和线段数和点的个数一致(都是8个)。

 

红色点的坐标(横坐标是整数)分别是:

个数和长方形的长的数值是一致的(是6)

 

绿色点的坐标(纵坐标是整数)分别是:

个数和长方形的宽的数值是一致的(是4)

 

可以看出,红色点和绿色点有2个点是重合的(图上用半红半绿的点标示),因此这些点合在一起就是如下(按照和起点的远近来进行排序)

 

于是该问题的求解过程可以如下表示:

1、求出横坐标是整数的点的个数,就是长方形长的数值。本题是6

2、求出纵坐标是整数的点的个数,就是长方体宽的数值。本题是4

3、求出步骤1和步骤2中重合的点的个数,也就是横纵坐标都是整数的点的个数。本题是2

4、问题的答案:步骤1的答案+步骤2的答案-步骤3的答案。本题是6+4-2=8

 

步骤1、2、3、4中,关键是步骤3,如何求出步骤1和步骤2中重合的点的个数,也就是横纵坐标都是整数的点的个数。

 

最大公约数:正整数a和b,若a能被b整除,则a是b的倍数,b是a的约数。正整数a和b中约数最大的那个称为a和b的最大公约数,记作gcd(a,b)

 

本题中,(4,6)=2,正好是步骤3的答数,是巧合么?不是,接下来我们来证明。

 

证明:长X、宽Y的长方形,对角线经过双整数点(横纵坐标都是整数)的个数为gcd(X,Y)(注:不算起点)

证:令x1=X/gcd(X,Y),y1=Y/gcd(X,Y)。则x1和y1都是整数,且x1和y1互质(除1以外,没有公约数)。

对角线所在的直线方程为

当x取整数时(1≤x≤X)时,要使y也是整数,则x必须取x1的倍数(这样才能把分母完全约掉)

而在1到X之间,x1的倍数一共有gcd(X,Y)个

证明完毕

 

综上所述:长方形长X,宽Y。X、Y都是正整数。长方形由长1、宽1的正方形组成。那么长方形的对角线穿过多少个正方形?

其解为:Ans=X+Y-gcd(X,Y),可以用下图表示

 

例如:

长6,宽4的长方形的对角线穿过6+4-gcd(6,4)=6+4-2=8个正方形

长5,宽3的长方形的对角线穿过5+3-gcd(5,3)=5+3-1=7个正方形

长12,宽8的长方形的对角线穿过12+8-gcd(12,8)=12+8-4=16个正方形

 

扩展到三维。长方体长X,宽Y,高Z。X、Y、Z都是正整数。长方体由长1、宽1、高1的正方体堆积而成。那么长方体的体对角线穿过多少个正方体?

长X、宽Y、高Z的立方体的体对角线的直线方程是

这个方程虽然有点怪,但是学过空间解析几何的都明白这个方程的正确性

 

求解的过程和二维的类似,也是找寻坐标是整数的点。可以用下图表示:

 

 

其解为:Ans=X+Y+Z-gcd(X,Y)-gcd(X,Z)-gcd(Y,Z)+gcd(X,Y,Z)

例如:

长5,宽3,高4的长方体的体对角线穿过5+3+4-gcd(5,3)-gcd(5,4)-gcd(3,4)+gcd(5,3,4)=5+3+4-1-1-1+1=10个正方体

长8,宽6,高3的长方体的体对角线穿过8+6+3-gcd(8,6)-gcd(8,3)-gcd(6,3)+gcd(8,6,3)=8+6+3-2-1-3+1=12个正方体

长12,宽8,高6的长方体的体对角线穿过12+8+6-gcd(12,8)-gcd(12,6)-gcd(8,6)+gcd(12,8,6)=12+8+6-4-6-2+2=16个正方体

 

 

下图是长5,宽3,高4的长方体的体对角线穿过正方体的示意图,一共10个正方体,你看清了么?

 

 

 

这个题历时若干年,总是百思不得其解。也是今朝灵光一闪,终于把该题解决了。也总算是一块石头落了地

时间: 2024-10-05 12:32:40

算法题——立方体的体对角线穿过多少个正方体?的相关文章

一个算法题,求答案啊啊啊啊

问题描述 一个算法题,求答案啊啊啊啊 白班 09:00-18:00 通班 09:00-21:00 每个人每个月通班数量必须等于早中班和中晚班数量之和 早中班 09:00-15:00 中晚班 15:00-21:00 假设:每月按照30计算. 排班规则: 1.每个人每个月固定休息6天连续上班天数不超过7天. 2.每天各班次上班的人数最低需求:8个白班5个通班1个早中班,2个中晚班. 3.每个月每个人的通班天数安排不超过8天. 4.每个人每个月早中班和中晚班的天数之和需要与通班天数相等. 5.每月最多

算法题:把阿拉伯金额转化为汉字表示的金额

n年没写算法题了,今天用了20分钟写了一个,要求如题,感觉算法有所退步,老了 using System; using System.Text; namespace money { class Program { static void Main(string[] args) { StringBuilder sb=new StringBuilder(); var strValue = Console.ReadLine(); var strlist = strValue.Split('.'); if

算法题:poj 2541 Binary Witch(KMP水过,逆序转换)

链接: http://poj.org/problem?id=2541 分析与总结: 做这题估算了下复杂度,觉得无论KMP再怎么快,这题暴力也肯定要超时的. 想了很久也没想出个好办法,于是决定暴力之,但是TLE了....于是就放了几天.之后看了下discuss ,这题的正解应该是状态压缩dp,不过目前我还不懂,跪了. 之后百度发现也可以用KMP水过,虽然是因为数据水才过的,不过这种思路很巧妙,值得借鉴! 直接暴力是枚举字符串的后面13个的字母,然后再用KMP匹配,这样的话,就绪要枚举多次,分别是

算法题:HDU 2594 Simpsons’ Hidden Talents(KMP)

链接: http://acm.hdu.edu.cn/showproblem.php?pid=2594 题目大意: 给两个字符串s1和s2, 求出是s1的前缀并且是s2的后缀的最长的字符串. 分析与总结: 真正理解好KMP算法,这题就是水题. 首先求出s1的失配函数,然后在s2中 寻找s1字符串. 在寻找字符串过程中,会有一个状态值j,这个值表示的是当前在s2中已经匹配 了多少个s1的字符. 所以,全部匹配完后,最后j的值就是以s2的最后一个字符结尾,和s1的前缀相匹 配的最长字符串.也就是所求的

算法题:uva 10318

题目链接: 首先,可以确定每个格子只能选一次,因为选任何大于0的偶数次,等于没有效果 一样. 然后,就可以把这题理解成从r*c的矩阵中选择一些格子进行"点亮"操作,使得最终所 有格子都是"亮"的状态.那么,每个格子要么有点亮操作,要么没有,总共复杂度为2^25,显然必须 进行减枝. 假设从第一行第一列开始,从左往右,从上往下一次依次选择,对于当前所在位置( x, y),它已经不能影响到x-2以前的行数了,所以当到x行时,如果第x-2行没有全部点亮,则进行减枝 . 此

算法题:uva 1330

题目链接: http://uva.onlinejudge.org/index.php? option=com_onlinejudge&Itemid=8&category=460&page=show_problem&problem=4076 以前做过一道一维的,这题只是变成了二维的,其他方法都一样.HDU 1506  Largest Rectangle in a Histogram   题解 代码1: #include<cstdio> #include<cs

求一个面试算法题答案。

问题描述 求一个面试算法题答案. 已知函数f()以相同的概率返回0或者1,求一个函数g()以相同的概率返回0-7之间的任意一个数字. 解决方案 其实这个题不难,可以考虑用2进制的方式来做.g(){return 4*f()+2*f()+f();} 希望能帮到你. 解决方案二: #includeint g(){srand(time(NULL));ret = rand()%8;return ret;}

经典算法题每日演练——第七题 KMP算法

原文:经典算法题每日演练--第七题 KMP算法       在大学的时候,应该在数据结构里面都看过kmp算法吧,不知道有多少老师对该算法是一笔带过的,至少我们以前是的, 确实kmp算法还是有点饶人的,如果说红黑树是变态级的,那么kmp算法比红黑树还要变态,很抱歉,每次打kmp的时候,输 入法总是提示"看毛片"三个字,嘿嘿,就叫"看毛片算法"吧. 一:BF算法      如果让你写字符串的模式匹配,你可能会很快的写出朴素的bf算法,至少问题是解决了,我想大家很清楚的知

java算法题,公司的笔试题

问题描述 java算法题,公司的笔试题 suppose you have N cakes, N is an interger>0 // at each time, you can either eat 1 cake, or 2 cakes or 3 cakes // PROBLEM: How many ways can you eat all N cakes // for example, N = 4, (1,2,1) and (1,1,2) are considered to be diffe