问题:
拉里在数学方面非常糟糕 - 他通常使用计算器,这在大学期间运作良好。不幸的是,在滑雪事故发生后,他和他的好伙伴Ryan在一个荒岛上被击中。他们现在正试图花一些时间搞清楚一些好问题,如果他不能回答,Ryan会吃Larry,所以他的命运取决于你!
这是一个非常简单的问题 - 给定数字N,K数小于N的方式可以加到N?
例如,对于N = 20和K = 2,有21种方式:
0+20
1+19
2+18
3+17
4+16
5+15
...
18+2
19+1
20+0
输入 每一行将包含一对数字N和K.N和K都是1到100的整数,包括1和100。输入将在2 0结束。 产量 由于拉里只对答案的最后几位感兴趣,因此对于每对数字N和K,在一行上打印单个数字mod 1,000,000。
示例输入
20 2
20 2
0 0
示例输出
21
21
解决方案代码:
#include<iostream>
#include<stdlib.h>
#include<stdio.h>
using namespace std;
#define maxn 100
typedef long ss;
ss T[maxn+2][maxn+2];
void Gen() {
ss i, j;
for(i = 0; i<= maxn; i++)
T[1][i] = 1;
for(i = 2; i<= 100; i++) {
T[i][0] = 1;
for(j = 1; j <= 100; j++)
T[i][j] = (T[i][j-1] + T[i-1][j]) % 1000000;
}
}
int main() {
//freopen("in.txt", "r", stdin);
ss n, m;
Gen();
while(cin>>n>>m) {
if(!n && !m) break;
cout<<T[m][n]<<endl;
}
return 0;
}
这个计算是如何推导出来的?
它是如何来的T[i][j] = (T[i][j-1] + T[i-1][j])
?
答案 0 :(得分:1)
注意 :我只使用 n 和 k (小写)来引用一些匿名变量。我总是使用N和K(大写)来表示问题中定义的N和K(总和和部分的数量)。
让C( n , k )成为 n 选择 k 的结果,然后解决方案问题是C(N + K - 1,K - 1),假设那些K数是非负的(或者即使对于N = 0和K = 2,也会有无限多的解)。
由于K数是非负的,并且总和N是固定的,我们可以将问题看作:在K人中划分糖果的方法有多少。我们可以将糖果分成一条线来分开糖果,并在糖果之间放置(K-1)分离器。 (K-1)分离器将糖果分成K部分的糖果。从另一个角度来看,它也像在(N + K - 1)位置中选择(K - 1)位置放入分隔符,然后其余的位置是糖果。因此,这解释了为什么方式的数量是N +(K-1)选择(K-1)。
然后问题减少到如何找到C的最低有效位( n , k )。 (由于maxn
中定义的N和K的最大值为100,我们不必担心算法是否达到O(n 3 )。
计算使用此组合身份C( n , k )= C( n - 1 , k )+ C( n , k - 1 )(Pascal's rule)。实现的聪明之处在于它不存储C( n , k )(组合结果表,这是一个锯齿状数组),但它存储换句话说是C(N,K)。身份实际上存在于T[i][j] = (T[i][j-1] + T[i-1][j])
:
T[K][N]
将直接存储结果,并根据上面得出的数学结果,是C(N + K - 1,K - 1)的(最低有效数字)。 / LI>
将T[i][j] = (T[i][j-1] + T[i-1][j])
重写为等效的数学结果:
C(i + j-1,i-1)= C(i + j-2,i-1)+ C(i + j-2,i-2),根据同一性是正确的。
程序将逐行填充数组:
T[i][j] = (T[i][j-1] + T[i-1][j])
,它将引用前一行,以及同一行的前一个元素,这两个元素都已在之前的迭代中填充。答案 1 :(得分:0)
这是一个着名的问题 - 您可以查看解决方案here
将N个相同球放入K盒的方法有多少。
以下算法是针对您的问题的动态编程解决方案:
将D [i,j]定义为我的数字小于j的方式的数量,可以总结为j。
0&lt; = i&lt; = N. 1&lt; = j&lt; = K
每个j的D [j,1] = 1。
其中j&gt; 1你得到:
D[i,j] = D[i,j-1] + D[i-1,j-1] +...+ D[0,j-1]
答案 2 :(得分:0)
设C(x,y)为x的结果选择y,然后T[i][j]
的值等于:C(i - 1 + j, j)
。
你可以通过归纳来证明这一点。
基本情况:
T[1][j] = C(1 - 1 + j, j) = C(j, j) = 1
T[i][0] = C(i - 1, 0) = 1
对于诱导步骤,使用公式(对于0 <= y <= x):
C(x,y) = C(x - 1, y - 1) + C(x - 1, y)
因此:
C(i - 1 + j, j) = C(i-1+j - 1, j - 1) + C(i-1+j - 1, j) = C(i-1+(j-1), (j-1)) + C((i-1)-1+j, j)
或换句话说:
T[i][j] = T[i,j-1] + T[i-1,j]
现在,正如之前提到的 nhahtdh ,您要寻找的值是C(N + K - 1,K - 1) 等于:
T[N+1][K-1] = C(N+1-1+K-1, K-1)
(模数1000000)
答案 3 :(得分:0)
该问题被称为“整数分区问题”。基本上存在n的k分区的递归计算,但是你的解决方案只是它的动态编程版本(非递归和自下而上的计算)。