Acwing 271. 杨老师的照相排列(线性dp求方案数)

Acwing 271. 杨老师的照相排列

题目

有 n 个人,编号 1 ~ n。要站成 k 排,现在给出每排的人数,保证从前往后不递增。现在给出总人数,求符合要求的总方案数。

分析

https://www.bilibili.com/video/av69678938

根据闫氏 dp 分析法,做 dp 先要划分集合,弄清除每个集合代表的意义。

dp[a][b][c][d][e]dp[a][b][c][d][e] 代表 5 排人数分别为 a, b, c, d, e,时的方案数,这时 dpdp 数组的每个元素代表一种特定的轮廓方案数的集合。枚举集合最后一个元素位置,划分集合。

进而得出状态转移方程。

#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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章