2021年下学期《C语言程序设计》作业16-2019年下学期期末考试
Description | ||
Blocks题目描述给你一个n块积木,每个积木块都是立方体,现在把它们排列一排,成m列,要求每列上至少有1个积木,且从左到右,每列的积木数量呈严格单调下降。比如8块积木,排成3列,那么合法的安排方案为 输入第一行是一个整数T(1≤T≤1000),表示样例的个数。 以后每个样例占一行,为两个整数 n(1≤n≤100),m(1≤m≤10)。 输出依次每行输出一个样例的结果,为一个整数。 |
题意理解:把n块积木分为m列,使得每一列的积木数严格单调递减。
例如将45块积木分为9列,那么987654321是合法的。987654123是非法的。
通过猜想,n块积木分为m列的方案数铁定与先前的状态有关。
我们知道,如果能将(36)块积木按要求分为(8)列,那么在最高位的左边放上9块积木,那么就能得到最高位为9,将(36+9)块积木分为(9)列的方案数。
#include<stdio.h>
long long int biao[105][105][15];//第一维是总积木数,第二维是最左边的积木数,第三维是列数
void dab()
{
int t, i, j, k, l;
for(i = 1; i <= 100; i++)
{
biao[i][i][1] = 1;//在DP中,我们管无法通过或不需要通过递推式得出的答案叫初始值,也称为base。
for(j = 2; j <= 10; j++)
{
for( k = j; k <= i; k++) //枚举最左边的积木数
{
for( l = k - 1; l > 0; l--)//L的初始值为k-1,保证了L会严格小于k
{
biao[i][k][j] += biao[i - k][l][j - 1];
}
}
}
}
}
int main()
{
dab();
long long int sum ;
int T, n, m;
scanf("%d", &T);
while(T--)
{
sum = 0;
scanf("%d %d", &n, &m);
for(int i = 0; i <= n; i++)
{
sum += biao[n][i][m];
}
printf("%I64d\n", sum);
}
}
有些人会问,为什么不能只用二维数组来解决。
在生活中,有个叫后效性的东西,说的是,当前的决策能对未来的决策造成影响。
对应这个题就是,最左边的积木数会限制你推导出向左扩展的方案数。
在DP中,也有个交后效性的东西,说的是当前状态的转移会导致未来状态无法正确转移。
而我们开三维数组的目的就是为了迎合这样的后效性。
9块积木分为三堆。
ans=f[9][1][3]+f[9][2][3]+f[9][3][3]+f[9][4][3]+f[9][5][3]+f[9][6][3]+f[9][7][3]+f[9][8][3]+f[9][9][3]
而f[9][5][3]=f[8][1][2]+f[7][2][2]+f[6][3][2]+f[5][4][2]