この post によれば、次のコードを介して数値のすべての約数を取得できます。
for (int i = 1; i <= num; ++i){
if (num % i == 0)
cout << i << endl;
}
たとえば、番号24
の約数は1 2 3 4 6 8 12 24
です。
関連する投稿を検索したところ、良い解決策は見つかりませんでした。これを達成するための効率的な方法はありますか?
私の解決策:
しかし、それは良いものではないようです。
因子は対になっています。 1
と24
、2
と12
、3
と8
、4
と6
。
アルゴリズムを改善するには、num
に至るまでの代わりにnum
の平方根を反復処理し、num / i
を使用してペアの因子を計算します。
あなたは本当にsqrt(num)* sqrt(num)= numとしてnumの平方根までチェックする必要があります:
これらの行の何か:
int square_root = (int) sqrt(num) + 1;
for (int i = 1; i < square_root; i++) {
if (num % i == 0&&i*i!=num)
cout << i << num/i << endl;
if (num % i == 0&&i*i==num)
cout << i << '\n';
}
これまでに科学で知られているアルゴリズムの複雑さ(多項式の複雑さを持つアルゴリズム)の意味で効率的な方法はありません。したがって、すでに提案されているように平方根まで反復することは、できる限り優れています。
主にこのため、現在使用されている暗号の大部分は、任意の整数の素因数分解を計算するのに非常に時間がかかるという仮定に基づいています。
私のコードは次のとおりです。
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
#define pii pair<int, int>
#define MAX 46656
#define LMT 216
#define LEN 4830
#define RNG 100032
unsigned base[MAX / 64], segment[RNG / 64], primes[LEN];
#define sq(x) ((x)*(x))
#define mset(x,v) memset(x,v,sizeof(x))
#define chkC(x,n) (x[n>>6]&(1<<((n>>1)&31)))
#define setC(x,n) (x[n>>6]|=(1<<((n>>1)&31)))
// http://zobayer.blogspot.com/2009/09/segmented-sieve.html
void sieve()
{
unsigned i, j, k;
for (i = 3; i<LMT; i += 2)
if (!chkC(base, i))
for (j = i*i, k = i << 1; j<MAX; j += k)
setC(base, j);
primes[0] = 2;
for (i = 3, j = 1; i<MAX; i += 2)
if (!chkC(base, i))
primes[j++] = i;
}
//http://www.geeksforgeeks.org/print-all-prime-factors-of-a-given-number/
vector <pii> factors;
void primeFactors(int num)
{
int expo = 0;
for (int i = 0; primes[i] <= sqrt(num); i++)
{
expo = 0;
int prime = primes[i];
while (num % prime == 0){
expo++;
num = num / prime;
}
if (expo>0)
factors.Push_back(make_pair(prime, expo));
}
if ( num >= 2)
factors.Push_back(make_pair(num, 1));
}
vector <int> divisors;
void setDivisors(int n, int i) {
int j, x, k;
for (j = i; j<factors.size(); j++) {
x = factors[j].first * n;
for (k = 0; k<factors[j].second; k++) {
divisors.Push_back(x);
setDivisors(x, j + 1);
x *= factors[j].first;
}
}
}
int main() {
sieve();
int n, x, i;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> x;
primeFactors(x);
setDivisors(1, 0);
divisors.Push_back(1);
sort(divisors.begin(), divisors.end());
cout << divisors.size() << "\n";
for (int j = 0; j < divisors.size(); j++) {
cout << divisors[j] << " ";
}
cout << "\n";
divisors.clear();
factors.clear();
}
}
最初の部分Sieve()は、素数を見つけてprimes []配列に入れるために使用されます。リンクをクリックして、そのコードの詳細を確認してください(ビットごとのふるい)。
2番目の部分primeFactors(x)は、入力として整数(x)を取り、その素因数と対応する指数を見つけ、それらをベクトルfactor []に入れます。たとえば、primeFactors(12)は次のようにfactor []に値を入力します。
factors[0].first=2, factors[0].second=2
factors[1].first=3, factors[1].second=1
12 = 2 ^ 2 * 3 ^ 1として
3番目の部分setDivisors()は、ベクトルfactor []を使用してxのすべての約数を計算するために再帰的に自身を呼び出し、それらをベクトルdivisors []に入れます。
Intに適合する任意の数の約数を計算できます。また、非常に高速です。
あまり大きくない数のすべての素因数を見つけるための多くの良い解決策があります。私が指摘したいのは、一度それらを取得すると、すべての要因を取得するために計算は必要ないということです。
if N = p_1^{a}*p_{2}^{b}*p_{3}^{c}.....
すべての要因がzeroa回発生する可能性があるため、要因の数は明らかに(a+1)(b+1)(c+1)....
です。
例えば12 = 2^2*3^1
なので、3*2 = 6
の要素があります。 1,2,3,4,6,12
======
私はもともと、あなたはただ明確な要素の数が欲しいと思っていました。しかし、同じロジックが適用されます。指数の可能な組み合わせに対応する数値のセットを反復処理します。
したがって、上記の例では:
00
01
10
11
20
21
6
要因を提供します。
int result_num;
bool flag;
cout << "Number Divisors\n";
for (int number = 1; number <= 35; number++)
{
flag = false;
cout << setw(3) << number << setw(14);
for (int i = 1; i <= number; i++)
{
result_num = number % i;
if (result_num == 0 && flag == true)
{
cout << "," << i;
}
if (result_num == 0 && flag == false)
{
cout << i;
}
flag = true;
}
cout << endl;
}
cout << "Press enter to continue.....";
cin.ignore();
return 0;
}
for (int i = 1; i*i <= num; ++i)
{
if (num % i == 0)
cout << i << endl;
if (num/i!=i)
cout << num/i << endl;
}
//Try this,it can find divisors of verrrrrrrrrry big numbers (pretty efficiently :-))
#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
#include<conio.h>
using namespace std;
vector<double> D;
void divs(double N);
double mod(double &n1, double &n2);
void Push(double N);
void show();
int main()
{
double N;
cout << "\n Enter number: "; cin >> N;
divs(N); // find and Push divisors to D
cout << "\n Divisors of "<<N<<": "; show(); // show contents of D (all divisors of N)
_getch(); // used visual studio, if it isn't supported replace it by "getch();"
return(0);
}
void divs(double N)
{
for (double i = 1; i <= sqrt(N); ++i)
{
if (!mod(N, i)) { Push(i); if(i*i!=N) Push(N / i); }
}
}
double mod(double &n1, double &n2)
{
return(((n1/n2)-floor(n1/n2))*n2);
}
void Push(double N)
{
double s = 1, e = D.size(), m = floor((s + e) / 2);
while (s <= e)
{
if (N==D[m-1]) { return; }
else if (N > D[m-1]) { s = m + 1; }
else { e = m - 1; }
m = floor((s + e) / 2);
}
D.insert(D.begin() + m, N);
}
void show()
{
for (double i = 0; i < D.size(); ++i) cout << D[i] << " ";
}
this アプローチのJava実装は次のとおりです。
public static int countAllFactors(int num)
{
TreeSet<Integer> tree_set = new TreeSet<Integer>();
for (int i = 1; i * i <= num; i+=1)
{
if (num % i == 0)
{
tree_set.add(i);
tree_set.add(num / i);
}
}
System.out.print(tree_set);
return tree_set.size();
}