the problem of integer partitioning is one of the classical propositions in the algorithm
The so-called integer division, refers to a positive integer n written in the following form:
N=m1+m2+m3+....+mi (where Mi is a positive integer and 1<=mi<=n), then {m1,m2,m3,...., mi} is a partition of N.
If the maximum value in {m1,m2,m3,...., mi} is not more than M, that is, MAX{M1,M2,M3,...., mi} <= m, it is said to belong to an m partition of N. Here we remember the number of M division of N is f (n,m);
For example, when n=4, it has 5 partitions: {4}, {3,1}, {2,2}, {2,1,1}, {1,1,1,1};
Note: 4=1+3 and 4=3+1 are considered to be the same division.
The problem is to find all the dividing numbers of N, that is, F (n,n). Here we consider the method of F (n,m).
Method One: Recursive method
Depending on the relationship between N and M, consider the following:
(1) When n=1, regardless of the value of M (m>0), there is only one division, that is {1};
(2) When m=1, no matter how much n value (n>0), there is only one division, that is, {1,1,.... 1,1,1};
(3) When n=m, according to whether the partition contains N, can be divided into two situations:
(a) In the case of a partition containing N, only one, that is, {n};
(b) The case where n is not included in the division, at which point the largest number in the division is certainly smaller than N, that is, all of N (n-1);
Therefore, f (n,n) = 1 + f (n, n-1).
(4) When the n<m, because there is no negative number in the division, it is equivalent to F (n,n);
(5) When n>m, according to whether the division contains m, can be divided into two situations:
(a) The case where M is included in the partition, that is {m,{x1,x2,x3,..., XI}, where {x1,x2,x3,..., XI} and is n-m, may reappear M, therefore is (N-M) the M division, so the number of this division is F (n-m, M);
(b) where M is not included in the division, all values in the division are smaller than m, i.e. N (m-1) and the number is F (n, m-1);
Therefore, f (n,m) = f (n-m,m) + f (n, m-1).
By synthesizing all the above situations, we can see that the above conclusions have the characteristics of recursive definition, among them (1) and (2) belong to the condition of regression, (3) and (4) belong to special case, and the situation (5) is a general case, which belongs to the recursive method, whose essence is to solve the problem by reducing N or M to achieve the regression condition.
Its recursive expression is shown below.
Reference Source 1.1 (recursive version (slower))
#include <stdio.h>
#define MAXNUM/ /maximum//
recursive method for integer partitioning
unsigned long getpartitioncount (int n , int max)
{
if (n = = 1 | | max = = 1)
{return
1;
}
if (n < max)
{return
getpartitioncount (n, n);
}
if (n = = max)
{return
1 + getpartitioncount (n, n-1);
}
else
{return
getpartitioncount (N-max, max) + Getpartitioncount (n, max-1);
}
}
int main (int argc, char **argv)
{
int n;
int m;
unsigned long count;
while (1)
{
scanf ("%d", &n);
if (n<=0) return
0;
M=n;
Count = Getpartitioncount (n, m);
printf ("%d\n", count);
}
return 0;
}
method Two: Dynamic programming
Considering the use of recursion, many of the recursive recursive computation, so that not only in time overhead, which is too slow operation, such as 120 of the time required 3 seconds, 130 of the time it takes 27 seconds, when the computer 200 .... Calculate 10 minutes has not been calculated ... In view of this, you can use the idea of dynamic programming, the principle of the same as above, divided into three cases, just use an array to replace the original recursion, can see the source code, the source code provides two versions of Recursive + record version and array version 2.1 recursive record version
This version uses an array tag, which, if previously computed, invokes the contents of the array directly, otherwise the calculation of the child recursion, so that each time the calculation is calculated, reduce the number of redundant source code as follows:
* *----------------------------------------------* Author:newplan * date:2015-04-01 * emai L:XXXXXXX * Copyright:newplan-----------------------------------------------* * #include <iostream> #d
Efine Maxnum 100//highest number of unsigned long ww[maxnum*11][maxnum*11];
unsigned long dynamic_getpartitioncount (int n, int max);
using namespace Std;
int main (int argc, char **argv) {int n;
int m;
unsigned long Count;
while (1) {cin>>n;
Cout<<dynamic_getpartitioncount (n,n) <<endl;
return 0;
unsigned long dynamic_getpartitioncount (int n, int max) {if (n = = 1 | | max = = 1) {ww[n][max]=1;
return 1;
} if (n < max) {Ww[n][n]=ww[n][n]? Ww[n][n]: Dynamic_getpartitioncount (n, N);
return ww[n][n];
} if (n = = max) {ww[n][max]=ww[n][n-1]?1+ww[n][n-1]:1 + dynamic_getpartitioncount (n, n-1);
return Ww[n][max]; else {ww[n][max]=ww[n-Max][max]?
(Ww[n-max][max]): Dynamic_getpartitioncount (N-max, Max); WW[N][MAX]+=WW[N][MAX-1]?
(Ww[n][max-1]): Dynamic_getpartitioncount (n, max-1);
return Ww[n][max]; }
}
2.2 Dynamic programming of array notation (from small to large)
Considering the calculation of ww[10][10]=ww[10][9]+1, so in every calculation is used before the record, so you can start from small to large program, so that when the larger number of calls have been calculated the smaller records, the program is directly with the loop can complete the task, Avoids the overhead of duplicate computations and space stacks. Source code:
/*----------------------------------------------
* Author : Newplan
* Date : 2015-04-01
* Email : xxxxxxx
* Copyright:newplan
-----------------------------------------------*
* Include <iostream>
#define Maxnum //highest number of
unsigned long ww[maxnum*11][maxnum*11];
unsigned long dynamic_getpartitioncount (int n, int max);
using namespace std;
int main (int argc, char **argv)
{
int n;
int m;
unsigned long count;
while (1)
{
cin>>n;
Cout<<dynamic_getpartitioncount (n,n) <<endl;
}
return 0;
}
unsigned long dynamic_getpartitioncount (int n, int max)
{for
(int i=1;i<=n;i++) for
(int j=1;j<=i ; j + +
{
if (j==1| | i==1)
{
ww[i][j]=1;
}
else
{
if (j==i)
ww[i][j]=ww[i][j-1]+1;
else if ((i-j) <j)
ww[i][j]=ww[i-j][i-j]+ww[i][j-1];
else
ww[i][j]=ww[i-j][j]+ww[i][j-1];
}
return Ww[n][max];
}
Three methods effect contrast is very obvious, before writing this blog test data 200, dynamic programming version input directly calculate the result, now this piece of blog finished,, the use of recursion has not calculated results ...
Method Three: the parent function
Let's look at the problem from another angle, the "parent function" perspective.
The so-called parent function, which is a polynomial g (x) about x:
have g (x) = a0 + a1*x + a2*x^2 + a3*x^3 + ...
Then we call g (x) the sequence (a0, A1, A2,.....) 's parent function. On the idea of the parent function we don't do more analysis.
We consider from the integer division, assuming that a division of N, 1 of the occurrence of the number of a1,2 is recorded as the number of a2,.....,i as AI,
Apparently there are: AK <= n/k (0<= k <=n)
So the partition number F (n,n) of N, which is a combination of n numbers from 1 to N, can theoretically be infinitely repetitive, that is, the number is random, so that their synthesis is n. Obviously, the number I can have the following possible, appear 0 times (that is not appear), 1 times, 2 times, ..., k times and so on. The number I is represented by (X^i), and the number I (x^ (i*k)), which appears K, does not appear in 1 representations.
For example, the number 2 is indicated by x^2, 2 2 is indicated by x^4, 3 2 is represented by X^6, and K 2 is represented by X^2K.
For all possible combinations of 1 to N, we can say:
G (x) = (1 + x + x^2 + x^3 + ... + x^n) * (1 + x^2 + x^4 + x^6 + ...) .... (1 + x^n)
= g (x,1) *g (x,2) *g (x,3) *....*g (x,n)
= a0 + a1*x + a2*x^2 +...+ an*x^n + ...//expand
In the expression above, the polynomial in each bracket represents all possible cases in which the number I participates in the partition. Therefore, the polynomial expands, because the x^a *x^b = x^ (a+b), so X^i represents the division of I, after the expansion (x^i) of the factor is the number of I, that is, f (n,n) = an.
So we found the parent function g (x) of the integer partition; the remaining problem is that we need to find all the coefficients of the expansion of G (x).
For this reason, we have to do polynomial multiplication first, it is not difficult for us. We put a polynomial about X in an integer array a[], a[i] represents the coefficients of the x^i, namely:
G (x) = A[0] + a[1]x + a[2]x^2 + ... + a[n]x^n;
The code for polynomial multiplication is as follows, where the array A and B represent two polynomials to multiply, and the results are stored in the array C.
Reference topic: Hdu:1028:ignatius and the Princess III reference Source:
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
const int n=10005;
int c1[n],c2[n];
int main ()
{
int n,i,j,k;
while (Cin>>n)
{
if (n==0) break;
for (i=0;i<=n;i++)
{
c1[i]=1;
c2[i]=0;
}
for (i=2;i<=n;i++)
{for (
j=0;j<=n;j++) for (
k=0;k+j<=n;k+=i)
c2[k+j]+=c1[j];
for (j=0;j<=n;j++)
{
c1[j]=c2[j];
C2[j]=0
}
}
cout<<c1[n]<<endl;
}
return 0;
}
Method 4:5 Boundary number theorem
Set the nth number of Pentagon, then, the sequence is: 1, 5, 12, 22, 35, 51, 70, ...
The corresponding figure is as follows:
To set the generation function for the Pentagon number, then there are:
The above is the case of Pentagon number. The following is the content of the Pentagon number theorem:
The Pentagon theorem is a mathematical theorem discovered by Euler, which describes the characteristics of Euler function expansion. The expansion of Euler functions is as follows:
After the Euler function is expanded, some of the minor items are eliminated, leaving only the minor items of 1, 2, 5, 7, 12, ... Of the items, the left side of the second square is just a generalized Pentagon number.
The relationship between Pentagon number and partition function
The reciprocal of Euler functions is the parent function of the partition function, namely:
Which is the partition function of K.
The upper-type fits the Pentagon number theorem, which is:
At n>0, the coefficients on the right side of the equation are 0, and the coefficients of the two sides of the equation are compared, which can be
So we can get the recursive type of the partition function p (n):
For example, when n=10, there are:
So, by using the recursion above, we can compute the number of integers (n) of N in a very fast way.
Reference Examples:
Hud4651:partition Source:
#include <iostream> using namespace std;
#define MYDATA Long Long const MYDATA mod=1000000007;
#define AMS 100005 MYDATA Pp[ams];
MYDATA Asist[2*ams]; void Myinit () {for (int i=0;i<ams;i++) {//* calculates the five-angle number (normal five-angle number is 1,5,12,22 ... k* (3*k-1)/2)/* This section, you need to work out the partition function (1,2,5,7,12,1
5,22,26 ... [k* (3*k-1)/2,k* (3*k+1)/2])/asist[2*i]=i* (i*3-1)/2;
asist[2*i+1]=i* (i*3+1)/2;
} void MyMethod () {pp[1]=1;
pp[2]=2;
Pp[0]=1;
for (int i=3;i<ams;i++) {int k=0;
int flags;
pp[i]=0; /*PP[N]=PP[N-1]+PP[N-2]-PP[N-5]-PP[N-7]+PP[12]+PP[15]-.... .....
[+PP[N-K*[3K-1]/2] + pp[n-k*[3k+1]/2]]*/for (int j=2;asist[j]<=i;j++) {/* Description: +mod is required in the formula, otherwise the output may be wrong (possibly negative).
flags=k&2;
if (!flags) pp[i]= (pp[i]+pp[i-asist[j]]+mod)%mod;
else pp[i]= (pp[i]-pp[i-asist[j]]+mod)%mod;
k++;
k%=8;
int main () {int t,n;
Myinit ();
MyMethod ();
cin>>t;
while (t--) {cin>>n;
cout<<pp[n]<<endl; } return 0;
}
Additional:
given an integer n, output the possible form of this integer split (that is, the output is all)
Using recursion
The entire output is similar to a tree to decompose 6 For example, the process is shown below
Source code implementation:
#include <stdio.h>//Use an array to record the value int set[100] that is generated in the recursive process before it needs to be repeatedly output;
Used in the recursive process to determine whether recursion to the deepest, output carriage return int k; This function represents the case where n is split using an integer not more than M, and I is used to represent the number of records that already exist for the set array length void q (int n,int m,int i) {if (n==k&&n!=m) {//This time recursively
The stack has been returned to the top of a branch and the output carriage return//Reset counter i is 0 printf ("\ n");
i=0;
} if (n==1) {//when n is 1, it means that only 1 printf ("1") can be represented;
Return
else if (m==1) {//when M is 1, means to output N m add for (int i=0; i<n-1; i++) printf ("1+");
printf ("1");
Return
} if (n<m) {q (n,n,i);
} if (n==m) {//when n equals M, arrives at this recursive sum of a leaf, at this time need to output more than one space, indicating that the next output is another leaf printf ("%d", n);
Output the number of previously recorded leaves above the leaf before recursively outputting another leaf, as shown on the 1 for (int j=0; j<i; j + +) printf ("%d+", set[j));
Q (n,m-1,i);
} if (n>m) {//if n is greater than M, using m as the decomposition, first print out the m+ form printf ("%d+", m);
Recording the value of the node m as a tree and making I set[i++]=m;
Recursive output m+ after decomposition Q (n-m,m,i);
After recursion, you need to back up the array record one, back to the previous node, as shown in the process 2 i--;
Executes another branch, outputting the recorded data before the next recursion, as shown on the 3 for (int j=0; j<i; j + +) printf ("%d+", set[j));
Recursive output Another branch condition Q (n,m-1,i);
int main () {int n; while (scanf ("%d", &n)!=eof) {if (n<=0) {printf ("Please input a positive interger.\n
\ n ");
Continue
} k=n;
Q (n,n,0);
printf ("\ n \ nthe");
return 0;
}