整数划分问题将一个整数n划分成几个正整数,几个正整数的和为n,如:
6
5 + 1
4 + 2, 4 + 1 + 1
3 + 3, 3 + 2 + 1, 3 + 1 + 1 + 1
2 + 2 + 2, 2 + 2 + 1 + 1, 2 + 1 + 1 + 1 + 1
1 + 1 + 1 + 1 + 1 + 1
纸上书写某个整数的划分时会先选一个较大的数,再分剩下的和,由此想到使用整个数序中允许最大的那个数作为状态变量。
DP表达式F(N,M),N表示当前划分的整数,M表示划分出的数列中允许的最大的数。
如果N或者M为1,易知F(N,M)=1;
如果N==M,在划分N时可以使用N(==M),也可以不使用,使用N的话只有一种情况,不使用N时状态表达式为F(N,M-1),故F(N,M) = F(N,M-1)+1;
如果N<M,F(N,M)=F(N,N);
如果N>M,同样在划分N时可以使用M,也可以不使用,使用M的话状态表达式为F(N-M,M),不使用的话状态表达式为F(N,M-1),故F(N,M) = F(N-M,M)+F(N,M-1);
谨记这里定义的状态的意义,整个DP就是一个状态转移的过程。
简单写个程序:
#include <stdio.h>
__int64 split(int n, int m)
{
if(n < 1 || m < 1)
return 0;
if(n == 1 || m == 1)
return 1;
if(n < m)
return split(n, n);
if(n == m)
return (split(n, m - 1) + 1);
if(n > m)
return (split(n, m - 1) + split((n - m), m));
}
int main()
{
int n ;
scanf("%d",&n);
while ( n != 0 )
{
printf("%d 的划分数: %I64d/n", n, split(n, n));
scanf("%d",&n);
}
}