数学的アルゴリズムの一般的な問題
コンピュータの世界では、我々は通常、まだいくつかの数学の問題を解決する必要があり、ここで忘れの速度を遅くすることを望んで、問題を要約するために、いくつかの一般的な数学的なアルゴリズムがあります。
最大公約数と最小公倍数
最大公約数
陽性は整数、bは条約の最大公約数である一般的な使用において、bのすべての公約数の最大数を意味gcd(a, b)
し、Bの最大公約数を表すために、ユークリッドアルゴリズム(ヒラメを解決するために使用最大公約数位相分割)。
次の定理に基づいてユークリッドアルゴリズム:
、bは正の整数、GCDれるセット(A、B)= GCD(%b)は
証明:R kおよびbは商によって分割されているセットA = KB + R、得られた余り
そこR = A - キロバイト設立
dはaとbの公約数でみましょう、
次いで、R = - 除数KB、R、D有しても
したがって、Dは、BとRの公約数であります
およびr =%のB、Bの公約数と%のBを有するdは
また、このように除数DとB、A、B、および%Bの除数の両方
なぜならDの任意の性質のもの、及びbは公約数がBの除数および%Bで有します
A = kbの除数R、B、及び同様の理由%のB + Bの除数であり、および
したがって除数と除数B、%bおよびbが全て等しいので、最大公約数が等しいです
即GCD(A、B)= GCD(B、%b)は
場合<B、結果はaとbの交換がある場合> Bは、その後、データがすぐにこの定理の大きさによって小さくすることができます。その境界再帰そう?我々はすべて知っているように、整数値0のいずれかと最大公約数があり、この結論は、再帰的な境界線として使用することができます。その結果、二つの重要な再帰的な取得します。
- 再帰:GCD(A、B)= GCD(B、%のB)
- 再帰境界:GCD(A、0)= A
その後、次のコードを取得することができます。
int gcd(int a, int b) {
if(b == 0) return a;
else return gcd(b, a % b);
}
最小公倍数
一般的な使用のLCM(b)はaとbの最小公倍数を表現します。
基づくことが解決の最大公約数の最小公倍数。場合およびB所与dの最大公約数、直ちに最小公倍数が取得できAB&/ D実際の動作では、それはより適切な表現があるので、** AB **はオーバーフローできる/ DB。
すなわち、aとbの最大公約数、積集合bのセットと、aとbの最小公倍数、およびセット、マルチAB共通因子が一度に計算されるの一環として、我々は共通因子を取り除くために必要があります
スコア4つの操作
二つの画分の分子と分母、その必要な演算結果を所定の四則手段のスコアを、以下に表すために、画分を簡素化する方法について説明します。
分数表現と簡素化
分数表現
スコアのために、書き込みの最も単純な形態は、不適切な画分を書かれている、すなわち、元の番号を保持し、分子分母が大きいか小さいかどうか、構造体を保持するために使用することができます。
struct Fraction{
int up, down;
};
3つのルール:
- スコアが負の場合非負ダウン、そして構成する分子が負になることができます
- スコアは、正確にゼロ、0予め定められている分子である場合、分母は1であります
- 分子と1以外に公約数を分母ません
画分を簡素化
簡略化は、主に製造するために使用されるフラクションの変数は、このように手順は、次の3つのステップに分割されている還元、分数として表現の3つの要件を満たします。
- 分子と分母はその反対の数になってきたので、分母が、負の場合ダウン
- 0の分子までの場合は、1の分母を聞かせて
- 約点:分子は次に分母dで分割されるように、分母の絶対値および分子最大公約数dの絶対値を求めます
コードは以下の通りであります:
Fraction reduction(Fraction result) {
if(result.down < 0) { // 分母为负数,令分子分母都变味相反数
result.up = -result.up;
result.down = -result.down;
}
if(result.up == 0) { // 如果分子为 0,令分母为 1
result.down = 1;
}else {
int d = gcd(abs(result.up), abs(result.down)); // 分子分母的最大公约数
result.up /= d;
result.down /= d; // 约去最大公约数
}
return result;
}
スコア4つの操作
スコアは、加算と減算点についてする必要があるため、式の分離を必要と式について計算することができます。
// 加法
Fraction add(Fraction f1, Fraction f2) {
Fraction result;
result.up = f1.up * f2.down + f2.up * f1.down;
result.down = f1.down * f2.down;
return reduction(result);
}
// 减法
Fraction minu(Fraction f1, Fraction f2) {
Fraction result;
result.up = f1.up * f2.down - f2.up * f1.down;
result.down = f1.down * f2.down;
return reduction(result);
}
// 乘法
Fraction mul(Fraction f1, Fraction f2) {
Fraction result;
result.up = f1.up * f2.up;
result.down = f2.down * f2.down;
return reduction(result);
}
// 除法
Fraction divide(Fraction f1, Fraction f2) {
Fraction result;
result.up = f1.up * f2.down;
result.down = f1.down * f2.up;
return reduction(result);
}
分数出力
出力スコアの要件を対象とする必要があり、実質上、以下の注意事項があります。
- 出力スコア、その最初の簡素化のために必要になる前に
- 分母Rダウンスコアは、スコアは整数、通常そのまま出力分子であることを示し、1であれば
- フラクションR場合絶対値最大の分子が分母ダウンより大きい、スコアが不適切画分であり、この時間は出力されるべきことを示す分数の形の、すなわち、整数部分r.up / r.down、分子部分は、ABS(r.up) %のダウン
- 画分は、上記Rのための適切な画分を満足しない場合に説明し、出力としてあります
以下は、出力ケースです。
void showResult(Fraction r) {
r = reduction(r);
if(r.down == 1) printf("%lld", r.up);
else if(abs(r.up) > r.down) {
printf("%d %d/%d", r.up / r.down, abs(r.up) % r.down, r.down);
}else {
printf("%d %d", r.up, r.down);
}
}
素数
また、素数素数として知られ、その数は1に加えて、独自のクラスを参照し、別の整数で割り切れません。すなわち、任意の正の整数をN、(1 <<n)の整数任意の正のための場合 、 されn % a != 0
、その後素数を知らNの数は、他の従事。特別な注意は素数、また複合でもありません。
素数的判断
nが2,3、......、N-1で割り切れるであるかどうかNは数が素数であるかどうかを決定するには、素数を決定するために、場合にのみ分割することができない、判断する必要があります。しかし、我々はSQRT(n)は約デジタル数より大きいが存在する場合、次いで、SQRT(N)程度である数が存在しなければならない、それを発見した未満、我々はわずか2からSQRT(N)に決定されます。
コードは以下の通りであります:
bool isPrime(int n) {
if(n <= 1) return false;
int sqr = (int)sqrt(n); // 根号 n
for(int i = 2; i <= sqr; i++) {
if(n % i == 0) return false;
}
return true; // n 是素数
}
nがない近い上位の範囲の下限をint型の変数にある場合は、単純な文言があります:
bool isPrime(int n) {
if(n <= 1) return false;
for(int i = 2; i * i <= n; i++) {
if(n % i == 0) return false;
}
return true;
}
アッパー(もちろん10私はオーバーフローを* int型の変数に近い範囲で結合した場合につながっ書かれた質問9以下が安全になります)、溶液は長い長いi型として定義され、彼らはオーバーフローしません。
プライムテーブルを取得します
我々は、すべての素数の広い範囲を見るために必要がある場合は、それを行うには簡単な方法はありませんか?
「スクリーニング」のスクリーニング方法の多くの種類が非常に簡単に理解することである、核となるアイデアは、次のとおりです。
その倍数のすべてのアウト雑草に、各素数のためのすべての数字を列挙する小型から大型までのアルゴリズム、および残りは素数あり、その過程で、我々はスタートコンディション与えられた必要な唯一のものは後に、2が素数であるということですこれは、プロセスサイクルによって得ることができます。
小前のステップに多数の、そうでない場合は画面に到達するAが素数でない場合は、A未満の素数が存在しなければならないので、それは、素数である必要があり、それは選別されなければなりません
[I]が偽の場合、非素数である場合は、[I]がtrueの場合、我々は、ブール配列画面をシミュレートするために使用することができ、その後、素数は、あります。
bool isPrime[maxn];
vector<int> prime;
void getPrime() {
for(int i = 0; i < maxn; i++) {
isPrime[i] = true; // 开始认为所有的都是素数
}
isPrime[0] = isPrime[1] = false;
for(int i = 2; i < maxn; i++) {
if(!isPrime[i]) {
continue; // 如果是非质数则跳过
}
prime.push_back(i);
for(int j = i * i; j < maxn; j+=i) {
isPrime[j] = false;
}
}
return;
}
分解品質係数
いわゆる品質係数分解は正の整数を指すNプライム以上の形態の積として書かれます。
しかし、最終的にそれは我々が同様に最初の素数のテーブルを壊すかもしれないので、個別の素数の数の積として書くことがあります。:私たちは同様に品質係数を保持する構造体を定義した可能性があり、数があるように、各品質係数は、複数回表示される場合がありますので、
struct factor{
int x, cnt;
}fac[10];
それは素因数内に存在する場合、正の整数nは、[2、n]の範囲のために、これらの要因は以下であるか、またはSQRT(N)、次いでSQRTより多くても1つの大きい(N)において、アイデア表示されるように:
- pは、nの係数であるかどうかを決定する、SQRT(N)の範囲で素因数のすべてを列挙するための1
- pは、Nの因数である場合、アレイFAC素因数pに増加し、その数は0で初期化し、そしてpが要因である場合はnは、数pプラスので、各操作のために、分割絶えずさせ、N、P及び1、pは係数nまでではありません
- nは係数pでない場合は、スキップ
- nは、上記のステップ1の端部よりもさらに大きい場合、SQRT(n)の係数よりもn個大きいが記載され、この因子は、この時間FACアレイで添加しました。
コードは以下の通りであります:
/*
Author: Veeupup
*/
#include <cstdio>
#include <climits>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
const long maxn = 1e7;
vector<long> primes; // 保存质数
bool isPrime[maxn]; // 质数判断
// 质数表初始化
void Initial() {
fill(isPrime, isPrime + maxn, true); // 所有的数字都初始化为 true,为质数,随后筛
isPrime[0] = isPrime[1] = false;
for(long i = 2; i < maxn; i++) {
if(!isPrime[i])
continue; // 如果 i 不是质数,则跳过
primes.push_back(i);
for(long j = i * i; j < maxn; j += i) {
isPrime[j] = false; // i 的倍数被标记为合数
}
}
return;
}
struct Factor {
long x, cnt;
}fac[10]; // 保存质因子
int main()
{
Initial(); // 初始化质数表
long n, num = 0; // num 为不同质因子的个数
scanf("%ld", &n);
if(n == 1) {
printf("1=1");
}else {
printf("%ld=", n);
long sqr = (long)sqrt(n);
// 枚举根号 n 以内的质因子
for (int i = 0; i < primes.size() && primes[i] < sqr; i++)
{
if(n % primes[i] == 0) {
fac[num].x = primes[i];
fac[num].cnt = 0;
while (n % primes[i] == 0)
{
fac[num].cnt++;
n /= primes[i];
}
num++;
}
if(n == 1)
break;
}
if(n != 1) {
fac[num].x = n;
fac[num++].cnt = 1;
}
// 按照格式输出
for (int i = 0; i < num; i++)
{
if(i > 0) printf("*");
printf("%ld", fac[i].x);
if(fac[i].cnt > 1) {
printf("^%d", fac[i].cnt);
}
}
}
return 0;
}