为了满足题目中的身高限制条件,我们按身高从高到低安排每个人的位置,当前安排的同学可以安排在每排已安排同学的右边(准备安排的排人数不超过当前排的人数限制,不超过上一排已安排的人数),如果还有空排,也可以安排在最靠上的空排。
比如上图,当前我们准备安排身高排名第八的同学,该同学可以可以安排在第 排,第 排和第 排。 注意到前 7 个人我们只关心每排的人数,在每排的人数确定以后,他们的位置不影响第 个同学的选择,这满足动态规划的无后效性。
接下来我们考虑如何设计状态,我们关心当前总共已安排的人数,每排的人数。所以状态设计为 ,表示总共站了 个人,其中每排的人数分别是 。那么
。
在具体实现的时候,因为空间限制,有一些优化,请参考代码。
#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[]); a5++) {
(a1 > ) f[a1][a2][a3][a4][a5] += f[a1 - ][a2][a3][a4][a5];
(a2 > ) f[a1][a2][a3][a4][a5] += f[a1][a2 - ][a3][a4][a5];
(a3 > ) f[a1][a2][a3][a4][a5] += f[a1][a2][a3 - ][a4][a5];
(a4 > ) f[a1][a2][a3][a4][a5] += f[a1][a2][a3][a4 - ][a5];
(a5 > ) f[a1][a2][a3][a4][a5] += f[a1][a2][a3][a4][a5 - ];
}
cout << f[x[]][x[]][x[]][x[]][x[]] << ;
}
{
(cin >> k && k != ) ();
}
从 开始循环可以避免大量的 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 <= (a4, x[]); a5++) {
f[a1][a2][a3][a4][a5] += f[a1 - ][a2][a3][a4][a5]
+ f[a1][a2 - ][a3][a4][a5]
+ f[a1][a2][a3 - ][a4][a5]
+ f[a1][a2][a3][a4 - ][a5]
+ f[a1][a2][a3][a4][a5 - ];
}
cout << f[x[]][x[]][x[]][x[]][x[]] << ;
}
{
(cin >> k && k != ) ();
}