给定一个数字N
,打印它可以表示为多少种方式
N = a + b + c + d
与
1 <= a <= b <= c <= d; 1 <= N <= M
我的观察:
For N = 4: Only 1 way - 1 + 1 + 1 + 1
For N = 5: Only 1 way - 1 + 1 + 1 + 2
For N = 6: 2 ways - 1 + 1 + 1 + 3
1 + 1 + 2 + 2
For N = 7: 3 ways - 1 + 1 + 1 + 4
1 + 1 + 2 + 3
1 + 2 + 2 + 2
For N = 8: 5 ways - 1 + 1 + 1 + 5
1 + 1 + 2 + 4
1 + 1 + 3 + 3
1 + 2 + 2 + 3
2 + 2 + 2 + 2
So I have reduced it to a DP solution as follows:
DP[4] = 1, DP[5] = 1;
for(int i = 6; i <= M; i++)
DP[i] = DP[i-1] + DP[i-2];
我的观察是正确的还是我遗漏了任何东西。我没有任何测试用例可以运行。如果方法正确或错误,请告诉我。
答案 0 :(得分:9)
这不正确。这是正确的:
让DP[n,k]
成为将n
表示为k
数字总和的方式。
然后你正在寻找DP[n,4]
。
DP[n,1] = 1
DP[n,2] = DP[n-2, 2] + DP[n-1,1] = n / 2
DP[n,3] = DP[n-3, 3] + DP[n-1,2]
DP[n,4] = DP[n-4, 4] + DP[n-1,3]
我只会解释最后一行,你可以马上看到,为什么其他人都是真的。
让我们来看一个n=a+b+c+d
的案例。
如果是&gt; 1,然后n-4 = (a-1)+(b-1)+(c-1)+(d-1)
是DP[n-4,4]
的有效总和。
如果a = 1,则n-1 = b+c+d
是DP[n-1,3]
的有效总和。
同样相反:
对于每个有效n-4 = x+y+z+t
,我们都有一个有效的n=(x+1)+(y+1)+(z+1)+(t+1)
。
对于每个有效n-1 = x+y+z
,我们都有一个有效的n=1+x+y+z
。
答案 1 :(得分:3)
不幸的是,你的再现是错误的,因为对于n = 9,解是6,而不是8。
如果p(n,k)是将n分割成k个非零整数部分的方法的数量,那么我们有
ul.nav
因为存在值为1的分区(在这种情况下取出该部分会产生n-1的分区为k-1个部分),或者您可以从每个分区中减去1,从而产生n-k的分区。很容易证明这个过程是一个双射,因此再次发生。
<强>更新强>
对于特定情况k = 4,OEIS告诉我们还有另一个线性递归仅依赖于n:
p(0,0) = 1
p(n,k) = 0 if k > n or (n > 0 and k = 0)
p(n,k) = p(n-k, k) + p(n-1, k-1)
这种复发可以通过标准方法解决,以获得明确的公式。我写了一个小SAGE script来解决它并得到以下公式:
a(n) = 1 + a(n-2) + a(n-3) + a(n-4) - a(n-5) - a(n-6) - a(n-7) + a(n-9)
OEIS也gives the following simplification:
a(n) = 1/144*n^3 + 1/32*(-1)^n*n + 1/48*n^2 - 1/54*(1/2*I*sqrt(3) - 1/2)^n*(I*sqrt(3) + 3) - 1/54*(-1/2*I*sqrt(3) - 1/2)^n*(-I*sqrt(3) + 3) + 1/16*I^n + 1/16*(-I)^n + 1/32*(-1)^n - 1/32*n - 13/288
我尚未验证。
答案 2 :(得分:1)
#include <iostream>
using namespace std;
int func_count( int n, int m )
{
if(n==m)
return 1;
if(n<m)
return 0;
if ( m == 1 )
return 1;
if ( m==2 )
return (func_count(n-2,2) + func_count(n - 1, 1));
if ( m==3 )
return (func_count(n-3,3) + func_count(n - 1, 2));
return (func_count(n-1, 3) + func_count(n - 4, 4));
}
int main()
{
int t;
cin>>t;
cout<<func_count(t,4);
return 0;
}
答案 3 :(得分:0)
我认为函数f(N,m,n)的定义,其中N是我们想要产生的和,m是和中每个项的最大值,n是总和中的项数应该工作。
如果N> 1,则将p(N,m,n)定义为n = 1为0。 m,否则为N.表示n> 1,f(N,m,n)=对于f(S-t,t,n-1)从1到N的所有t的总和
这表示从右到左设置每个术语。
然后您可以使用此关系解决问题,可能使用memoization。
对于最大n = 4,并且N = 5000,(并且当有0种可能性时巧妙地实现以快速计算出来),我认为这对于大多数目的而言可能足够快地计算。