Acwing 271. 楊老師的照相排列
題目
有 n 個人,編號 1 ~ n。要站成 k 排,現在給出每排的人數,保證從前往後不遞增。現在給出總人數,求符合要求的總方案數。
分析
https://www.bilibili.com/video/av69678938
根據閆氏 dp 分析法,做 dp 先要劃分集合,弄清除每個集合代表的意義。
用 代表 5 排人數分別爲 a, b, c, d, e,時的方案數,這時 數組的每個元素代表一種特定的輪廓方案數的集合。枚舉集合最後一個元素位置,劃分集合。
進而得出狀態轉移方程。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF = 0x3f3f3f;
const int N = 31;
int k, s[5];
ll dp[N][N][N][N][N];
int main() {
while (scanf("%d", &k), k) {
memset(s, 0, sizeof(s));
memset(dp, 0, sizeof(dp));
for (int i = 0; i < k; i++)
scanf("%d", &s[i]);
dp[0][0][0][0][0] = 1;
for (int a = 0; a <= s[0]; a++)
for (int b = 0; b <= min(s[1], a); b++)
for (int c = 0; c <= min(s[2], b); c++)
for (int d = 0; d <= min(s[3], c); d++)
for (int e = 0; e <= min(s[4], d); e++) {
ll &v = dp[a][b][c][d][e];
if (a && a - 1 >= b) v += dp[a-1][b][c][d][e];
if (b && b - 1 >= c) v += dp[a][b-1][c][d][e];
if (c && c - 1 >= d) v += dp[a][b][c-1][d][e];
if (d && d - 1 >= e) v += dp[a][b][c][d-1][e];
if (e) v += dp[a][b][c][d][e-1];
}
printf("%lld\n", dp[s[0]][s[1]][s[2]][s[3]][s[4]]);
}
return 0;
}