这题就是个公式,代码极简单。但我想,真正明白这题原理的人并不多。很多人只是随便网上一搜,找到公式a了就行,其实这样对自己几乎没有提高。

鉴于网上关于这题的解题报告中几乎没有讲解原理的,我就多说几句,也不是严格的证明,给大家分享一下。

题目是说有p人或q人吃蛋糕,需要提前把蛋糕切好而能同时满足这两种情况,使蛋糕的块数最少。为了方便表述,不妨设p < q

首先,记p和q的最小公倍数为m,则把蛋糕平均切成m块,一定是能满足条件的,但这不是最优解,暂记为解法①。

我们的工作就是把解法①的这m块中的一些尽可能合并起来(也就是之前不切开),使块数尽可能少。那么怎么合并呢?

第一个能肯定的是,每一块最大为1/q,否则当来的人数是q时就不行了。而最小呢,就是1/m。所以解法②可以这样:先切出p份1/q大小的块,剩下的部分全切成1/m大小的,这样显然也是能满足要求的。

比如p = 2, q = 3,那么就切成1/3, 1/3, 1/6, 1/6。这个例子这恰好是最优解,但并不总是所有情况都这样。

比如p = 6, q = 10,最优应该切成1/10, 1/10, 1/10, 1/10, 1/10, 1/10, 1/15, 1/15, 1/15, 1/15, 1/30, 1/30, 1/30, 1/30

而p = 24, q = 60的最优解应该是1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/60, 1/120, 1/120, 1/120, 1/120, 1/120, 1/120, 1/120, 1/120, 1/120, 1/120, 1/120, 1/120, 1/120, 1/120, 1/120, 1/120, 1/120, 1/120, 1/120, 1/120, 1/120, 1/120, 1/120, 1/120

聪明的人应该已经看出来了,其实就是继续把后面的1/m的小块合并,这些小块越来越小,最后最小的都是1/m大小的。而中间大小的块的数量怎么确定呢?

比如p = 6, q = 10时,1/15块的数量应该是4而不是6,因为如果数量是6,仅仅能满足当人数为6的情况(这时每人吃一块1/10的,加一块1/15的),但当人数为10时,这些1/15的小块无法组成1/10的大块。所以必须预留一些更小的块出来。这时,1/15的块只要保留(q-p)=4块即可。剩下的情况就是递归处理,也就是说,当切出6个1/10的块后,接下来的问题等价于处理p = 10 - 6 = 4, q = 6的情况,只是这时剩下的蛋糕只是原来的4/10而已。

如果p < q/2时成立,比如当p = 24, q = 60时,切出24个1/60的块后,应该继续切出24个1/60的块,然后再考虑1/120的小块。

这个刚好就是辗转相除法求最大公约数的过程。具体的原理大家再细细品味。

下面是代码:

/*
* Author : ben
*/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
#include <stack>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <functional>
#include <numeric>
#include <cctype>
using namespace std; int gcd(int a, int b) {
int r;
while (b) {
r = a % b;
a = b;
b = r;
}
return a;
} int main() {
int p, q;
while (scanf("%d%d", &p, &q) == ) {
printf("%d\n", p + q - gcd(p, q));
}
return ;
}

hdu1722 bjfu1258 辗转相除法的更多相关文章

  1. C语言辗转相除法求2个数的最小公约数

    辗转相除法最大的用途就是用来求两个数的最大公约数. 用(a,b)来表示a和b的最大公约数. 有定理: 已知a,b,c为正整数,若a除以b余c,则(a,b)=(b,c). (证明过程请参考其它资料) 例 ...

  2. 辗转相除法求最大公约数,非goto

    #include<iostream> using namespace std; //不推荐用goto,当然用它更快 //辗转相除法求两数的最大公约数 int gcd(long int a, ...

  3. C实现辗转相除法求两个数的最大公约数

    什么是辗转相除法? 辗转相除法(又名欧几里德算法),它主要用于求两个正整数的最大公约数.是已知的最古老的算法. 用辗转相除法求132和72的最大公约数的步骤: 132 / 72 = 1 ... 60 ...

  4. C++中用辗转相除法求两个数的最大公约数和最小公倍数

    两个数的最大公约数:不能大于两个数中的最小值,算法口诀:小的给大的,余数给小的,整除返回小的,即最大公约数,(res=max%min)==0?  max=min,min=res return min; ...

  5. 九度OJ 1056--最大公约数 1439--Least Common Multiple 【辗转相除法】

    题目地址:http://ac.jobdu.com/problem.php?pid=1056 题目描述: 输入两个正整数,求其最大公约数. 输入: 测试数据有多组,每组输入两个正整数. 输出: 对于每组 ...

  6. 辗转相除法_欧几里得算法_java的实现(求最大公约数)

    辗转相除法,又被称为欧几里德(Euclidean)算法, 是求最大公约数的算法. 当然也可以求最小公倍数. 算法描述 两个数a,b的最大公约数记为GCD(a,b).a,b的最大公约数是两个数的公共素因 ...

  7. L - 辗转相除法(第二季水)

    Description The least common multiple (LCM) of a set of positive integers is the smallest positive i ...

  8. poj1580---欧几里得算法(辗转相除法)

    #include<stdio.h> #include<string.h> #include<string.h> ],str2[]; int len; int cal ...

  9. 辗转相除法求H.C.F小结

    辗转相除法 大纲: 问题 原理 反思 1.     问题 一个试题,请完成以下填空 下列程序是利用辗转相除法求H.C.F(最大公约数) include <stdio.h> int main ...

随机推荐

  1. 2013 Multi-University Training Contest 1 Cards

    数据不是很大,直接枚举约数,判断4个条件是否满足! 这样就得到4种卡片,总共2^4种情况,枚举各种情况即可!!! #include<iostream> #include<cmath& ...

  2. 关于Python的super用法

    Python中对象方法的定义很怪异,第一个参数一般都命名为self(相当于其它语言的this),用于传递对象本身,而在调用的时候则不必显式传递,系统会自动传递. 举一个很常见的例子: >> ...

  3. Project Euler 91:Right triangles with integer coordinates 格点直角三角形

    Right triangles with integer coordinates The points P (x1, y1) and Q (x2, y2) are plotted at integer ...

  4. platform_driver_register(),platform_device_register()区别

    设备与驱动的两种绑定方式:在设备注册时进行绑定及在驱动注册时进行绑定. 以一个USB设备为例,有两种情形: (1)先插上USB设备并挂到总线中,然后在安装USB驱动程序过程中从总线上遍历各个设备,看驱 ...

  5. No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK? 问题

    maven编译项目时出错,提示信息如下: [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3 ...

  6. OSSEC配置文件ossec.conf中添加mysql服务

    配置路径:/opt/ossec/etc/ossec.conf <ossec_config>   <global>     <email_notification>y ...

  7. 遍历并remove HashMap中的元素时,遇到ConcurrentModificationException

    遍历并remove HashMap中的元素时,遇到ConcurrentModificationException for (Map.Entry<ImageView, UserConcise> ...

  8. 3、REST风格的URL

    1.概述 HTTP协议里面,四个表示操作方式的动词:GET.POST.PUT.DELETE,它们分别对应四种基本的操作,GET用来获取资源,POST用来新建资源,PUT用来更新资源,DELETE用来删 ...

  9. linux PATH环境变量

    $PATH:决定了shell将到哪些目录中寻找命令或程序,PATH的值是一系列目录,当您运行一个程序时,Linux在这些目录下进行搜寻编译链接 shell下输出path值: echo $PATH: w ...

  10. Android移动应用开发中常见的经验技巧总结

    转:http://wwwdevstorecn/essay/essayInfo/6128.html 1. 对话保持的解决方案. 要求: 1.app中使用webview访问具体网站的内容,但是app与服务 ...