给定矩阵AxB,其包含整数> = 0。矩阵的每列的总和在从左向右移动时应该不减小。此外,B th 列(最后一列)的总和小于或等于A.
查找给定A和B的此类型的不同矩阵的数量。
我尝试使用递归和memoization解决它,如下所示 -
函数solve()是 -
ll solve(ll i,ll curlevel)
{
if(dp[i][curlevel]!=-1)
return dp[i][curlevel];
if(i<0)
return dp[i][curlevel]=0;
if(curlevel==B)
return dp[i][curlevel]=test(i,c);
if(curlevel>B)
return dp[i][curlevel]=0;
ll ans=0;
for(ll k=i;k>=0;k--)
{
ans+= test(i,A)* solve(k, curlevel+1);
}
return dp[i][curlevel]=ans;
}
功能测试定义如下─ (它计算一个总和的方式=&#39;总和可以作为不同的非负数的总和出现=&#39;地点&#39;)
ll test(ll sum,ll places)
{
if(mem[sum][places] != -1)
return mem[sum][places];
if(sum==0)
return mem[sum][places]=1;
if(places==0)
return mem[sum][places]=0;
ll val=0;
for(ll i=0;i<=sum;i++)
{
val+=test(sum-i,places-1);
}
return mem[sum][places]=val;
}
然而,这种方法太慢了。
有更快的方法吗?(也许是更好的组合方法)
答案 0 :(得分:0)
你必须预先计算分区数组 - A的整数分区数到A个非负数部分(包括零)并考虑部分顺序(即计算0 0 1和0 1 0等)。
修改强>
Partitions(k) = C(A + k - 1, A - 1)
A = 4的例子
Partitions[4] = C(7,3)=7!/(4!3!)=35
整个阵列:
Partitions = {1,4,10,20,35}
要计算分区,请使用表格旋转的Pascal三角形
1 1 1 1 1
1 2 3 4 5 //sum of 1st row upto ith element
1 3 6 10 15 //sum of 2st row
1 4 10 20 35 //sum of upper row
对于A = 1000,您需要大约1000 * sizeof(int64)内存(一行或两行)和大约10 ^ 6个模数加法。如果您需要对许多A值进行计算,只需存储整个表(8 MB)
然后使用以下公式:// 更正
S(columns, minsum) = Partitions[k] * Sum[k=minsum..A]{ S(columns - 1, k) }
S(1,k) = Partitions[k]
Result = Sum[k=0..A] { S[B,k] }
答案 1 :(得分:0)
从最后一列的最后一个单元格开始,如果该单元格的值为A,则最后一列中的所有其他单元格必须为0,因此在这种情况下,最后一列有1种可能的排列。
如果最后一个单元格的值为A-1,那么同一列中它旁边的单元格可以是0或1,因此有一种排列,其中最后一列与A-1和A-1排列相加列中的总和为A。
通常,递归函数是:
NumberOfArrangementsOfColumn( cells_remaining, value_remaining ){
if( value_remaining == 0 ) return 1;
if( cells_remaining == 1 ) return value_remaining + 1;
int total = 0;
for( int sub_value = 1; sub_value <= value_remaining; sub_value++ ){
total +=
NumberOfArrangementsOfColumn( cells_remaining - 1, sub_value );
}
return total;
}
此功能将确定最后一列的排列数量。然后,您需要为每个可能的值创建另一个递归函数,用于计算从倒数第二列开始的每个剩余列。