简体   繁体   English

如何找到总和给定数字的最小primatics数

[英]how to find the minimum number of primatics that sum to a given number

Given a number N (<=10000), find the minimum number of primatic numbers which sum up to N. 给定数N(<= 10000),找到总和为N的最小primatic数。

A primatic number refers to a number which is either a prime number or can be expressed as power of prime number to itself ie prime^prime eg 4, 27, etc. 一个primatic数字指的是一个数字,它可以是素数,也可以表示为素数对自身的幂,即素数,例如4,27等。

I tried to find all the primatic numbers using seive and then stored them in a vector (code below) but now I am can't see how to find the minimum of primatic numbers that sum to a given number. 我试图使用seive找到所有的primatic数字然后将它们存储在一个向量中(下面的代码),但现在我看不出如何找到总和给定数字的最小primatic数字。

Here's my sieve: 这是我的筛子:

#include<algorithm>
#include<vector>

#define MAX 10000

typedef long long int ll;

ll modpow(ll a, ll n, ll temp) {
    ll res=1, y=a;
    while (n>0) {
        if (n&1)
            res=(res*y)%temp;
        y=(y*y)%temp;
        n/=2;
    }
    return res%temp;
}


int isprimeat[MAX+20];

std::vector<int> primeat;

//Finding all prime numbers till 10000
void seive()
{
    ll i,j;
    isprimeat[0]=1;
    isprimeat[1]=1;
    for (i=2;  i<=MAX;  i++) {
        if (isprimeat[i]==0) {
            for (j=i*i;  j<=MAX;  j+=i) {
                isprimeat[j]=1;
            }
        }
    }
    for (i=2;  i<=MAX;  i++) {
        if (isprimeat[i]==0) {
            primeat.push_back(i);
        }
    }

    isprimeat[4]=isprimeat[27]=isprimeat[3125]=0;
    primeat.push_back(4);
    primeat.push_back(27);
    primeat.push_back(3125);
}

int main()
{
    seive();
    std::sort(primeat.begin(), primeat.end());
    return 0;
}

One method could be to store all primatics less than or equal to N in a sorted list - call this list L - and recursively search for the shortest sequence. 一种方法可以是在排序列表中存储小于或等于N的所有primatics - 调用此列表L - 并递归地搜索最短序列。 The easiest approach is "greedy": pick the largest spans / numbers as early as possible. 最简单的方法是“贪婪”:尽早选择最大跨度/数字。

for N = 14 you'd have L = {2,3,4,5,7,8,9,11,13} , so you'd want to make an algorithm / process that tries these sequences: 对于N = 14你有L = {2,3,4,5,7,8,9,11,13} ,所以你想要做一个尝试这些序列的算法/过程:

  1. 13 is too small 13太小了
  2. 13 + 13 -> 13 + 2 will be too large 13 + 13 - > 13 + 2会太大
  3. 11 is too small 11太小了
  4. 11 + 11 -> 11 + 4 will be too large 11 + 11 - > 11 + 4会太大
  5. 11 + 3 is a match. 11 + 3是一场比赛。

You can continue the process by making the search function recurse each time it needs another primatic in the sum, which you would aim to have occur a minimum number of times. 您可以通过在每次需要另一个primatic时使搜索功能递归来继续该过程,您可以将其目标发生在最小次数。 To do so you can pick the largest -> smallest primatic in each position (the 1st, 2nd etc primatic in the sum), and include another number in the sum only if the primatics in the sum so far are small enough that an additional primatic won't go over N . 为此,您可以选择每个位置中最大的 - >最小的primatic(总和中的第一个,第二个等),并且只有当到目前为止的总和中的primatics足够小以至于另外一个primatic时,才包括另一个数字。不会超过N

I'd have to make a working example to find a small enough N that doesn't result in just 2 numbers in the sum. 我必须做一个工作的例子来找到一个足够小的N ,它不会导致总和中只有2个数字。 Note that because you can express any natural number as the sum of at most 4 squares of natural numbers, and you have a more dense set L than the set of squares, so I'd think it rare you'd have a result of 3 or more for any N you'd want to compute by hand. 请注意,因为你可以将任何自然数表示为最多4个自然数的平方和,并且你有一个比正方形组更密集的集合L ,所以我认为很少有你得到3的结果对于你想要手动计算的任何N或者更多。

Dynamic Programming approach 动态规划方法

I have to clarify that 'greedy' is not the same as 'dynamic programming', it can give sub-optimal results. 我必须澄清“贪婪”与“动态编程”不同,它可以给出次优结果。 This does have a DP solution though. 这确实有一个DP解决方案。 Again, i won't write the final process in code but explain it as a point of reference to make a working DP solution from. 同样,我不会在代码中编写最终过程,而是将其作为制作工作DP解决方案的参考点进行解释。

To do this we need to build up solutions from the bottom up. 要做到这一点,我们需要从下到上构建解决方案。 What you need is a structure that can store known solutions for all numbers up to some N , this list can be incrementally added to for larger N in an optimal way. 您需要的是一种结构,可以为所有数字存储已知解决方案,最多可达N ,此列表可以以最佳方式逐步添加到更大的N

Consider that for any N , if it's primatic then the number of terms for N is just 1. This applies for N=2-5,7-9,11,13,16,17,19 . 考虑到对于任何N ,如果它是primatic,那么N的项数只是1.这适用于N=2-5,7-9,11,13,16,17,19 The number of terms for all other N must be at least two, which means either it's a sum of two primatics or a sum of a primatic and some other N . 所有其他N的术语数必须至少为2,这意味着它是两个primatics的总和或者primatic和其他N的总和。

The first few examples that aren't trivial: 前几个不小的例子:

6 - can be either 2+4 or 3+3 , all the terms here are themselves primatic so the minimum number of terms for 6 is 2. 6 - 可以是2+43+3 ,这里的所有术语本身都是primatic,所以6的最小术语数是2。

10 - can be either 2+8 , 3+7 , 4+6 or 5+5 . 10 - 可以是2+8 3+7 4+65+5 However 6 is not primatic, and taking that solution out leaves a minimum of 2 terms. 然而,6不是primatic,并采取该解决方案留下至少2个术语。

12 - can be either 2+10 , 3+9 , 4+8 , 5+7 or 6+6 . 12 - 可以是2+10 3+9 4+8 5+76+6 Of these 6+6 and 2+10 contain non-primatics while the others do not, so again 2 terms is the minimum. 其中6+62+10包含非primatics而其他不包含非primatics,因此2个术语最小。

14 - ditto, there exist two-primatic solutions: 3+11 , 5+9 , 7+7 . 14 -同上,存在两primatic解决方案: 3+115+97+7

The structure for storing all of these solutions needs to be able to iterate across solutions of equal rank / number of terms. 用于存储所有这些解决方案的结构需要能够跨越相同等级/数量的术语的解决方案。 You already have a list of primatics, this is also the list of solutions that need only one term. 您已经有一个primatics列表,这也是只需要一个术语的解决方案列表。

Sol[term_length] = list(numbers) . Sol[term_length] = list(numbers) You will also need a function / cache to look up some N 's shortest-term-length, eg S(N) = term_length iif N in Sol[term_length] 您还需要一个函数/缓存来查找N的最短项长度,例如S(N) = term_length iif N in Sol[term_length]

Sol[1] = {2,3,4,5 ...} and Sol[2] = {6,10,12,14 ...} and so on for Sol[3] and onwards. Sol[1] = {2,3,4,5 ...}Sol[2] = {6,10,12,14 ...}以及Sol[3]等等。

Any solution can be found using one term from Sol[1] that is primatic. 使用Sol[1]中的一个术语可以找到任何解决方案。 Any solution requiring two primatics will be found in Sol[2] . 任何需要两个primatics的解决方案都可以在Sol[2] Any solution requiring 3 will be in Sol[3] etc. 需要3的任何解决方案都在Sol[3]等。

What you need to recognize here is that a number S(N) = 3 can be expressed Sol[1][a] + Sol[1][b] + Sol[1][c] for some a,b,c primatics, but it can also be expressed as Sol[1][a] + Sol[2][d] , since all Sol[2] must be expressible as Sol[1][x] + Sol[1][y] . 你需要认识到的是,对于某些a,b,c primatics a,b,c S(N) = 3可以表示Sol[1][a] + Sol[1][b] + Sol[1][c] ,但它也可以表示为Sol[1][a] + Sol[2][d] ,因为所有Sol[2]必须表示为Sol[1][x] + Sol[1][y]

This algorithm will in effect search Sol[1] for a given N , then look in Sol[1] + Sol[K] with increasing K , but to do this you will need S and Sol structures roughly in the form shown here (or able to be accessed / queried in a similar manner). 这个算法实际上会搜索给定N Sol[1] ,然后在增加K查看Sol[1] + Sol[K] ,但为了做到这一点,你需要大致采用此处所示形式的SSol结构(或能够以类似的方式访问/查询)。

Working Example 工作实例

Using the above as a guideline I've put this together quickly, it even shows which multi-term sum it uses. 使用上面作为指导我快速地将它们放在一起,甚至可以显示它使用的多项和。

https://ideone.com/7mYXde https://ideone.com/7mYXde

I can explain the code in-depth if you want but the real DP section is around lines 40-64. 如果你愿意,我可以深入解释代码,但真正的DP部分是在40-64行左右。 The recursion depth (also number of additional terms in the sum) is k , a simple dual-iterator while loop checks if a sum is possible using the kth known solutions and primatics, if it is then we're done and if not then check k+1 solutions, if any. 递归深度(也是总和中附加项的数量)是k ,一个简单的双迭代器,而循环检查是否可以使用第k个已知解和primatics求和,如果是,那么我们就完成了,如果没有那么检查k + 1个解决方案,如果有的话。 Sol and S work as described. SolS按照描述工作。

The only confusing part might be the use of reverse iterators, it's just to make != end() checking consistent for the while condition (end is not a valid iterator position but begin is, so != begin would be written differently). 唯一令人困惑的部分可能是使用反向迭代器,它只是使!= end()检查while条件的一致性(end不是有效的迭代器位置但是start是,所以!= begin将以不同的方式写入)。

Edit - FYI, the first number that takes at least 3 terms is 959 - had to run my algorithm to 1000 numbers to find it. 编辑 - 仅供参考,第一个至少需要3个术语的数字是959 - 必须将我的算法运行到1000个数字才能找到它。 It's summed from 6 + 953 (primatic), no matter how you split 6 it's still 3 terms. 它总结为6 + 953(primatic),无论你如何分裂6,它仍然是3个术语。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM