为了满足题目中的身高限制条件,我们按身高从高到低安排每个人的位置,当前安排的同学可以安排在每排已安排同学的右边(准备安排的排人数不超过当前排的人数限制,不超过上一排已安排的人数),如果还有空排,也可以安排在最靠上的空排。
比如上图,当前我们准备安排身高排名第八的同学,该同学可以可以安排在第 1 排,第 2 排和第 4 排。 注意到前 7 个人我们只关心每排的人数,在每排的人数确定以后,他们的位置不影响第 8 个同学的选择,这满足动态规划的无后效性。
接下来我们考虑如何设计状态,我们关心当前总共已安排的人数,每排的人数。所以状态设计为 f(k,x1,x2,x3,x4,x5),表示总共站了 k 个人,其中每排的人数分别是 x1,x2,x3,x4,x5。那么
f(k,x1,x2,x3,x4,x5)=
f(k−1,x1−1,x2,x3,x4,x5)+
f(k−1,x1,x2−1,x3,x4,x5)+
f(k−1,x1,x2,x3−1,x4,x5)+
f(k−1,x1,x2,x3,x4−1,x5)+
f(k−1,x1,x2,x3,x4,x5−1)。
在具体实现的时候,因为空间限制,有一些优化,请参考代码。
#include <bits/stdc++.h>
using namespace std;
long long f[32][17][12][10][8];
int x[6], k;
void solve() {
for (int i = 1; i <= k; i++) cin >> x[i];
for (int i = k + 1; i <= 5; i++) x[i] = 0;
memset(f, 0, sizeof f);
f[0][0][0][0][0] = 1;
for (int a1 = 0; a1 <= x[1]; a1++)
for (int a2 = 0; a2 <= min(a1, x[2]); a2++)
for (int a3 = 0; a3 <= min(a2, x[3]); a3++)
for (int a4 = 0; a4 <= min(a3, x[4]); a4++)
for (int a5 = 0; a5 <= min(a4, x[5]); a5++) {
if (a1 > 0) f[a1][a2][a3][a4][a5] += f[a1 - 1][a2][a3][a4][a5];
if (a2 > 0) f[a1][a2][a3][a4][a5] += f[a1][a2 - 1][a3][a4][a5];
if (a3 > 0) f[a1][a2][a3][a4][a5] += f[a1][a2][a3 - 1][a4][a5];
if (a4 > 0) f[a1][a2][a3][a4][a5] += f[a1][a2][a3][a4 - 1][a5];
if (a5 > 0) f[a1][a2][a3][a4][a5] += f[a1][a2][a3][a4][a5 - 1];
}
cout << f[x[1]][x[2]][x[3]][x[4]][x[5]] << '\n';
}
int main() {
while (cin >> k && k != 0) solve();
}
从 1 开始循环可以避免大量的 if 判断。
#include <bits/stdc++.h>
using namespace std;
long long f[32][17][12][10][8];
int x[6], k;
void solve() {
for (int i = 1; i <= k; i++) cin >> x[i], x[i]++;
for (int i = k + 1; i <= 5; i++) x[i] = 1;
memset(f, 0, sizeof f);
f[1][1][1][1][1] = 1;
for (int a1 = 1; a1 <= x[1]; a1++)
for (int a2 = 1; a2 <= min(a1, x[2]); a2++)
for (int a3 = 1; a3 <= min(a2, x[3]); a3++)
for (int a4 = 1; a4 <= min(a3, x[4]); a4++)
for (int a5 = 1; a5 <= min(a4, x[5]); a5++) {
f[a1][a2][a3][a4][a5] += f[a1 - 1][a2][a3][a4][a5]
+ f[a1][a2 - 1][a3][a4][a5]
+ f[a1][a2][a3 - 1][a4][a5]
+ f[a1][a2][a3][a4 - 1][a5]
+ f[a1][a2][a3][a4][a5 - 1];
}
cout << f[x[1]][x[2]][x[3]][x[4]][x[5]] << '\n';
}
int main() {
while (cin >> k && k != 0) solve();
}