uvaoj 106 Fermat vs. Pythagoras 毕达哥拉斯三元组

16 篇文章 0 订阅

uvaoj 106 Fermat vs. Pythagoras 毕达哥拉斯三元组

给定方程x^2+y^2=z^2,在1到1000000范围内找出三元组(x,y,z)的数目,其中三元组要求x<y<z,并且x,y和z两两互质,并且求出不在任何三元组内的数的个数(并不限于两两互质)。

这个方程与勾股定理有密切的关系。

1.  勾股定理和勾股数(毕达哥拉斯数)
勾股定理可以说是全部数学中最古老也最家喻户晓的一个定理,在西方它被称为毕达哥拉斯定理(Pythagorean Theorem or Pythagoras' theorem),因为古希腊的数学家毕达哥拉斯(Pythagoras,572 BC—497 BC)最早证明了这个定理。据说,毕达哥拉斯发现这个定理后欣喜若狂,命人宰杀了一百头牛祭祀庆贺,故它又被戏称为“百牛定理”。
勾股定理的确是一个又简单又很“牛”的定理,它断言任意直角三角形斜边的平方等于两条直角边的平方之和,记两直角边的长为 a 和 b, 斜边的长为 c, 则一定有:
a^2  +  b^2   =  c^2
满足上述方程的正整数(a, b, c)被称为“勾股数”,也称为“毕达哥拉斯数”(Pythagorean numbers)或“毕达哥拉斯三元数组”(Pythagorean triplet),由勾股定理可知,这样的三个整数恰好能构成直接三角形的三条边。
最为大家熟悉的勾股数是(3, 4, 5),在二千多年前的中国古代数学著作《周髀算经》就有“勾三股四弦五”的记载,说明我们的老祖宗老早就知道了这组勾股数。中国古代把直角三角形的两条直角边分别称为“勾”和“股”,斜边称为“弦”,“勾三股四弦五”等于道出了勾股定理的一个特例,“勾、股各自乘,并而开方除之(则得弦)”,这是《周髀算经》中对勾股定理的一般表述(但书中并没有给出证明,长于计算,疏于推理和逻辑演绎是中国古代数学的一个特征)【注1】。

2.题目的做法

我们注意到如果三元(x,y,z)满足方程,那么(kx,ky,kz)也满足方程,所以我们只需要求出来所有两两互质的三元组,就可以得到所有的解。

首先可以证明x和y必为一奇一偶。因为互质,所以不能同为偶数。用反证法可以证明不同时为奇数。设x=2a+1,y=2b+1,则有z^2=4(a^2+b^2+a+b)+2,因为x^2和y^2为奇数,所以z^2也为奇数,有它为平方数,所以它必须能被四整除,这与前边的式子矛盾,所以x和y不能同时为奇数。

假设x为奇数,y为偶数,则z为奇数,2z与2x的最大公因数为2,2z和2x可分别写作
2z = (z + x) + (z - x)
2x = (z + x) - (z - x)
那么跟据最大公因数性质,z + x和z - x的最大公因数也为2,又因为:
(z + x)(z - x) = y^2,两边同除以4得:
((z + x) / 2)((z - x) / 2) = (y / 2)^2
故可令:
z + x = 2m^2, z - x = 2n^2
其中z = m^2 + n^2, x = m^2 - n^2(m与n互质,并且m和n一奇数一偶数,同理可证明)
则有:
y2 = z^2 - x^2 = 2m^2*2n^2 = 4m^2n^2
即y = 2mn。
综上所述,可得到下式:
x = m^2 - n^2, y = 2mn, z = m^2 + n^2. (m, n为任意自然数)
这里还有一个问题:题目要求统计(x, y, z)三元组的数量时只统计x,y和z两两互质的的情况,这个问题用上面的算法就可以解决了。但对于统计p的数量,题目并不限定三元组是两两互质的。但是上式不能生成所有x, y, z并不是两两互质的情况。然而假设x与y最大公因数w不为1,则z也必能被w整除,因此w为x, y, z三个数的公因数。归纳总结可知,所有非两两互质的x0, y0, z0都可由一组互质的x, y, z乘以系数得到。根据以上理论就可以快速的求解了

代码如下:

/*************************************************************************
	> File Name: 106.cpp
	> Author: gwq
	> Mail: gwq5210@qq.com 
	> Created Time: 2015年01月06日 星期二 19时20分08秒
 ************************************************************************/

#include <cmath>
#include <ctime>
#include <cctype>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>

#include <map>
#include <set>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <algorithm>

#define INF (INT_MAX / 10)
#define clr(arr, val) memset(arr, val, sizeof(arr))
#define pb push_back
#define sz(a) ((int)(a).size())

using namespace std;
typedef set<int> si;
typedef vector<int> vi;
typedef map<int, int> mii;
typedef long long ll;

const double esp = 1e-5;

#define N 1000010

int vis[N];

int gcd(int a, int b)
{
	return b == 0 ? a : gcd(b, a % b);
}

int main(int argc, char *argv[])
{
	int n;
	while (scanf("%d", &n) != EOF) {
		int ans1 = 0;
		int ans2 = 0;
		clr(vis, 0);
		for (int i = 2; i * i < n; ++i) {
			for (int j = 1; j < i; ++j) {
				int x = i * i - j * j;
				int y = 2 * i * j;
				int z = i * i + j * j;
				// i和j必须互质和一奇一偶
				if (i % 2 != j % 2 && x <= n && y <= n
						&& z <= n && gcd(i, j) == 1) {
					++ans1;
					for (int k = 1; k * z <= n; ++k) {
						vis[k * x] = 1;
						vis[k * y] = 1;
						vis[k * z] = 1;
					}
				}
			}
		}
		for (int i = 1; i <= n; ++i) {
			if (!vis[i]) {
				++ans2;
			}
		}
		printf("%d %d\n", ans1, ans2);
	}

	return 0;
}

注:

【注1】但中国古人也并不是完全缺乏证明的意识和才华,三国时吴国的赵爽在给《周髀算经》所作的注中就给出了勾股定理的一个漂亮的证明,他用的方法是面积割补法(即著名的赵爽弦图,2002年在北京召开的国际数学家大会上曾用赵爽弦图作为会徽)。

参考:

1)http://www.cnblogs.com/devymex/archive/2010/08/07/1799713.html

2)http://www.xieguofang.cn/Maths/Number_Theory/Fermats_Last_Theorem_1.htm

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值