hdu1722 bjfu1258 辗转相除法
这题就是个公式,代码极简单。但我想,真正明白这题原理的人并不多。很多人只是随便网上一搜,找到公式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 辗转相除法的更多相关文章
- C语言辗转相除法求2个数的最小公约数
辗转相除法最大的用途就是用来求两个数的最大公约数. 用(a,b)来表示a和b的最大公约数. 有定理: 已知a,b,c为正整数,若a除以b余c,则(a,b)=(b,c). (证明过程请参考其它资料) 例 ...
- 辗转相除法求最大公约数,非goto
#include<iostream> using namespace std; //不推荐用goto,当然用它更快 //辗转相除法求两数的最大公约数 int gcd(long int a, ...
- C实现辗转相除法求两个数的最大公约数
什么是辗转相除法? 辗转相除法(又名欧几里德算法),它主要用于求两个正整数的最大公约数.是已知的最古老的算法. 用辗转相除法求132和72的最大公约数的步骤: 132 / 72 = 1 ... 60 ...
- C++中用辗转相除法求两个数的最大公约数和最小公倍数
两个数的最大公约数:不能大于两个数中的最小值,算法口诀:小的给大的,余数给小的,整除返回小的,即最大公约数,(res=max%min)==0? max=min,min=res return min; ...
- 九度OJ 1056--最大公约数 1439--Least Common Multiple 【辗转相除法】
题目地址:http://ac.jobdu.com/problem.php?pid=1056 题目描述: 输入两个正整数,求其最大公约数. 输入: 测试数据有多组,每组输入两个正整数. 输出: 对于每组 ...
- 辗转相除法_欧几里得算法_java的实现(求最大公约数)
辗转相除法,又被称为欧几里德(Euclidean)算法, 是求最大公约数的算法. 当然也可以求最小公倍数. 算法描述 两个数a,b的最大公约数记为GCD(a,b).a,b的最大公约数是两个数的公共素因 ...
- L - 辗转相除法(第二季水)
Description The least common multiple (LCM) of a set of positive integers is the smallest positive i ...
- poj1580---欧几里得算法(辗转相除法)
#include<stdio.h> #include<string.h> #include<string.h> ],str2[]; int len; int cal ...
- 辗转相除法求H.C.F小结
辗转相除法 大纲: 问题 原理 反思 1. 问题 一个试题,请完成以下填空 下列程序是利用辗转相除法求H.C.F(最大公约数) include <stdio.h> int main ...
随机推荐
- java nio2
Buffer的基本用法 使用Buffer读写数据一般遵循以下四个步骤: 写入数据到Buffer 调用flip()方法 从Buffer中读取数据 调用clear()方法或者compact()方法 当向b ...
- Zookeeper安装部署
Zookeeper安装 1. 安装 wget http://www.apache.org/dist//zookeeper/zookeeper-3.3.6/zookeeper-3.3.6.tar.gz ...
- ios开发--27个提升效率的iOS开源库推荐
超长慎入列表: DZNEmptyDataSet(UI,空表格视图解算器) PDTSimpleCalendar(UI,drop-in日历组件) MagicalRecord(实施活跃记录模式的Core D ...
- KDE/QT与GNOME/GTK比较
转自:http://linux.chinaunix.net/bbs/thread-1125240-1-1.html 虽然在商业方面存在竞争,GNOME与KDE两大阵营的开发者关系并没有变得更糟,相反他 ...
- 函数执行到return就结束了
遇到return,函数就结束了,不会往下执行 测试: class User { String name; int age; boolean fun1(int i){ if(i==1){ return ...
- C++:虚函数的详解
5.4.2 虚函数详解 1.虚函数的定义 虚函数就是在基类中被关键字virtual说明,并在派生类重新定义的函数.虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问 ...
- Android handler真的是重新启动一个线程吗?
我们说handler是开启了另外一个线程,而且看代码的话确实是这样,实现了runnable接口,这在java中就是开启了一个线程,但是情况中的是这样吗?我们不妨来做个试验,如下 import andr ...
- Android如何获取开机启动项列表
static final String BOOT_START_PERMISSION = "android.permission.RECEIVE_BOOT_COMPLETED"; p ...
- js学习对象创建
Object.extend = function(destination, source) {for (var property in source) { destination[propert ...
- hdu 4635 Strongly connected(强连通)
考强连通缩点,算模板题吧,比赛的时候又想多了,大概是不自信吧,才开始认真搞图论,把题目想复杂了. 题意就是给你任意图,保证是simple directed graph,问最多加多少条边能使图仍然是si ...