这题就是个公式,代码极简单。但我想,真正明白这题原理的人并不多。很多人只是随便网上一搜,找到公式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. keystonejs

    开始之前先确保你已经安装了Node.js 0.10+ 和MongoDB v2.4+. 要使用KeystoneJS,你需要掌握合理的Javascript知识,并熟悉数据库概念之类的基础知识,会用 nod ...

  2. 李洪强iOS开之【零基础学习iOS开发】【02-C语言】04-常量、变量

    在我们使用计算机的过程中,会接触到各种各样的数据,有文档数据.图片数据.视频数据,还有聊QQ时产生的文字数据.用迅雷下载的文件数据等.这讲我们就来介绍C语言中数据的处理. 一.数据的存储 1.数据类型 ...

  3. 10、JPA_映射双向多对多的关联关系

    双向多对多的关联关系 双向多对多的关联关系(抽象成A-B)具体体现:A中有B的集合的引用,同时B中也有对A的集合的引用.A.B两个实体对应的数据表靠一张中间表来建立连接关系. 同时我们还知道,双向多对 ...

  4. get Status canceled 请求被取消

    1.chrome浏览器下状况: 2.环境: 一个页面A下 包含一个 iframe ,在子页面中用js点击A页面下的链接替换iframe内容脚本如下: window.parent.document.ge ...

  5. NDK(19)简单示例:ndk调用java基本方法、数组;使用stl、访问设备

    一.ndk调用java类示例 1,调用基本方法 /* * Class: com_example_ndksample_MainActivity * Method: ndkFindJavaClass * ...

  6. 面向对象设计Object Oriented Design

    http://www.codeproject.com/Articles/93369/How-I-explained-OOD-to-my-wife http://www.cnblogs.com/niyw ...

  7. Android Studio设置,鼠标放上去有提示

    设置如下: 1. 2. 勾选就可以了

  8. Junit单元测试的实例

    进行单元测试的代码 package JunitTest; import org.junit.Test; public class Calculator { private static int res ...

  9. hdu 1257 最少拦截系统(简单贪心)

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1257 虽然分类是dp感觉还是贪心 比较水 #include <iostream> #inclu ...

  10. poj 1195 Mobile phones(二维树状数组)

    树状数组支持两种操作: Add(x, d)操作:   让a[x]增加d. Query(L,R): 计算 a[L]+a[L+1]……a[R]. 当要频繁的对数组元素进行修改,同时又要频繁的查询数组内任一 ...