[英]A number as it's prime number parts
我必須打印代表給定數字的方式,因為它是素數部分。
讓我澄清一下:讓我說我得到了這個數字7.現在,首先,我必須找到所有小於7的素數,即2,3和5.現在,我可以用多少種方法總結這些數字(我可以使用我想要的一個數字),以便結果等於7? 例如,數字7有五種方式:
2 + 2 + 3
2 + 3 + 2
2 + 5
3 + 2 + 2
5 + 2
我完全迷失了這項任務。 首先,我想我會制作一系列可用的元素,如:{2,2,2,3,3,5}(7/2 = 3,所以2必須出現三次。相同的是3,得到兩個出現次數)。 之后,循環遍歷數組並選擇一個'leader'來確定我們在數組中的距離。 我知道解釋很可怕,所以這里是代碼:
#include <iostream>
#include <vector>
int primes_all[25] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97};
int main()
{
int number;
std::cin >> number;
std::vector<int> primes_used;
for(int i = 0; i < 25; i++) {
if(primes_all[i] < number && number-primes_all[i] > 1) {
for(int k = 0; k < number/primes_all[i]; k++)
primes_used.push_back(primes_all[i]);
}
else break;
}
int result = 0;
for(size_t i = 0; i < primes_used.size(); i++) {
int j = primes_used.size()-1;
int new_num = number - primes_used[i];
while(new_num > 1 && j > -1)
{
if(j > -1) while(primes_used[j] > new_num && j > 0) j--;
if(j != i && j > -1) {
new_num -= primes_used[j];
std::cout << primes_used[i] << " " << primes_used[j] << " " << new_num << std::endl;
}
j--;
}
if(new_num == 0) result++;
}
std::cout << result << std::endl;
system("pause");
return 0;
}
這根本行不通。 僅僅因為它背后的想法是錯誤的。 這是關於限制的一些細節:
此外,可以給出的最大數字是100.這就是為什么我將素數數組設置為低於100.隨着給定數字變大,結果變得非常快,稍后將需要BigInteger類,但這不是問題。
一些結果已知:
Input Result
7 5
20 732
80 10343662267187
所以...任何想法? 這是一個組合問題嗎? 我不需要代碼,只需要一個想法。 我仍然是C ++的新手,但我會管理
請記住,3 + 2 + 2不同於2 + 3 + 2.此外,如果給定的數字本身是素數,則不會計算。 例如,如果給定的數字是7,則只有這些總和有效:
2 + 2 + 3
2 + 3 + 2
2 + 5
3 + 2 + 2
5 + 2
7 <= excluded
動態編程是你的朋友。
考慮數字27。
如果7有5個結果,20有732個結果,那么你知道27個結果至少有(732 * 5)。 您可以使用預先計算的兩個變量系統(1 + 26,2 + 25 ......等)。 您不必重新計算25或26,因為您已經完成了它們。
您要搜索的概念是數字的“主要分區”。 數字的S分區是一種添加數字以達到目標的方式; 例如,1 + 1 + 2 + 3是7的分區。如果所有加數都是素數,則該分區是主分區。
我認為你的例子是錯的。 數字7通常被認為具有3個主要分區:2 + 2 + 3,2 + 5和7.加數的順序無關緊要。 在數論中,計算主要分區的函數是kappa,所以我們會說kappa(7)= 3。
kappa的通常計算分兩部分完成。 第一部分是計算數字素因子之和的函數; 例如,42 = 2·3·7,所以sopf(42)= 12。 注意,sopf(12)= 5,因為總和僅超過數字的不同因子,因此即使12 = 2·2·3,在總和的計算中也只包括一個2。
考慮到sopf,有一個很長的公式來計算kappa; 我會用LaTeX形式給它,因為我不知道如何在這里輸入它:\\ kappa(n)= \\ frac {1} {n} \\ left(\\ mathrm {sopf}(n)+ \\ sum_ { j = 1} ^ {n-1} \\ mathrm {sopf}(j)\\ cdot \\ kappa(nj)\\ right)。
如果您真的想要一個分區列表,而不僅僅是計數,那么@corsiKa指出了一個動態編程解決方案。
我在博客上更詳細地討論了主要分區,包括生成計數和列表的源代碼。
這是一個有效的實現,使用動態編程,如corsiKa建議,但不使用他描述的算法。
簡單地說:如果n
可以通過k
不同的路徑(包括單步路徑,如果它存在),並且p
是素數,那么我們通過將p
附加到n
所有路徑來構造到n+p
的k
路徑。 考慮到所有這樣的n < N
將產生到N
的有效路徑的詳盡列表。 所以我們只是總結了如此發現的路徑數量。
#include <iostream>
int primes_all[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97};
const int N_max = 85;
typedef long long ways;
ways ways_to_reach_N[N_max + 1] = { 1 };
int main()
{
// find all paths
for( int i = 0; i <= N_max; ++i ) {
ways ways_to_reach_i = ways_to_reach_N[i];
if (ways_to_reach_i) {
for( int* p = primes_all; *p <= N_max - i && p < (&primes_all)[1]; ++p ) {
ways_to_reach_N[i + *p] += ways_to_reach_i;
}
}
}
// eliminate single-step paths
for( int* p = primes_all; *p <= N_max && p < (&primes_all)[1]; ++p ) {
--ways_to_reach_N[*p];
}
// print results
for( int i = 1; i <= N_max; ++i ) {
ways ways_to_reach_i = ways_to_reach_N[i];
if (ways_to_reach_i) {
std::cout << i << " -- " << ways_to_reach_i << std::endl;
}
}
return 0;
}
用大整數類型替換typedef ways
留給讀者練習。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.