安排具备以下条件

时间:2015-06-10 10:55:15

标签: algorithm math dynamic-programming combinatorics

给定矩阵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;
}

然而,这种方法太慢了。

有更快的方法吗?(也许是更好的组合方法)

2 个答案:

答案 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;
}

此功能将确定最后一列的排列数量。然后,您需要为每个可能的值创建另一个递归函数,用于计算从倒数第二列开始的每个剩余列。