I have to print the number of ways you can represent a given number as it's prime number parts.
Let me clarify: Let's say I have been given this number 7. Now, first of all, I have to find all the prime numbers that are less than 7, which are 2, 3 and 5. Now, in how many ways can I summarize those numbers (I can use one number as many times I want) so that the result equals 7? For example, number 7 has five ways:
2 + 2 + 3
2 + 3 + 2
2 + 5
3 + 2 + 2
5 + 2
I'm totally lost with this task. First I figured I'd make an array of usable elements like so: { 2, 2, 2, 3, 3, 5 } (7/2 = 3, so 2 must appear three times. Same goes with 3, which gets two occurences). After that, loop through the array and choose a 'leader' that determines how far in the array we are. I know the explanation is horrible, so here's the code:
#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;
}
This simply doesn't work. Simply because the idea behind it is wrong. Here's a little details about the limits:
- Time limit: 1 second
- Memory limit: 128 MB
Also, the biggest number that can be given is 100. That's why I made the array of prime numbers below 100. The result grows very fast as the given number gets bigger, and will need a BigInteger class later on, but that's not an issue.
A few results known:
Input Result
7 5
20 732
80 10343662267187
SO... Any ideas? Is this a combinatory problem? I don't need code, just an idea. I'm still a newbie to C++ but I'll manage
Keep in mind that 3 + 2 + 2 is different than 2 + 3 + 2. Also, were the given number to be a prime itself, it won't be counted. For example, if the given number is 7, only these sums are valid:
2 + 2 + 3
2 + 3 + 2
2 + 5
3 + 2 + 2
5 + 2
7 <= excluded
Dynamic programming is your friend here.
Consider the number 27.
If 7 has 5 results, and 20 has 732 results, then you know that 27 has at least (732 * 5) results. You can use a two variable system (1 + 26, 2 + 25 ... etc) using the precomputed values for those as you go. You don't have to recompute 25 or 26 because you already did them.
The concept you are searching for is the "prime partitions" of a number. S partition of a number is a way of adding numbers to reach the target; for instance, 1+1+2+3 is a partition of 7. If all the addends are prime, then the partition is a prime partition.
I think your example is wrong. The number 7 is usually considered to have 3 prime partitions: 2+2+3, 2+5, and 7. The order of the addends doesn't matter. In number theory the function that counts prime partitions is kappa, so we would say kappa(7) = 3.
The usual calculation of kappa is done in two parts. The first part is a function to compute the sum of the prime factors of a number; for instance, 42=2·3·7, so sopf(42)=12. Note that sopf(12)=5 because the sum is over only the distinct factors of a number, so even though 12=2·2·3, only one 2 is included in the calculation of the sum.
Given sopf, there is a lengthy formula to calculate kappa; I'll give it in LaTeX form, since I don't know how to enter it here: \kappa(n) = \frac{1}{n}\left(\mathrm{sopf}(n) + \sum_{j=1}^{n-1} \mathrm{sopf}(j) \cdot \kappa(n-j)\right).
If you actually want a list of the partitions, instead of just the count, there is a dynamic programming solution that @corsiKa pointed out.
I discuss prime partitions in more detail at my blog, including source code to produce both the count and the list.
Here's an efficient implementation which uses dynamic programming like corsiKa suggests, but does not use the algorithm he describes.
Simply: if n is reachable via k distinct paths (including the single-step one, if it exists), and p is prime, then we construct k paths to n+p by appending p to all paths to n. Considering all such n < N will produce an exhaustive list of valid paths to N. So we just sum the number of paths so discovered.
#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;
}
- Demo: http://ideone.com/xWZT8v
Replacing the typedef ways with a big integer type is left as an exercise to the reader.
来源:https://stackoverflow.com/questions/14218882/a-number-as-its-prime-number-parts