AcWing 271. 杨老师的照相排列 (多维线性DP)

杨老师的照相排列

这道题想了很长时间,最后看题解才学会的,呜呜呜,我好菜呀!!

dp分析:

dp三要素:状态、阶段、决策。

  1. 状态: d p [ a ] [ b ] [ c ] [ d ] [ e ] dp[a][b][c][d][e] dp[a][b][c][d][e]从第 1 1 1排到第 5 5 5排放a~e人数的方案数。
  2. 状态划分:每一行存放的人数。
  3. 转移方程:如果前一行人数大于后一行人数:dp += dp(某一行人数-1);
  4. 边界: d p [ 0 ] [ 0 ] [ 0 ] [ 0 ] [ 0 ] = 1 dp[0][0][0][0][0] = 1 dp[0][0][0][0][0]=1
  5. 目标: d p [ a ] [ b ] [ c ] [ d ] [ e ] dp[a][b][c][d][e] dp[a][b][c][d][e]

题解:

  1. 我们从一个小的集合中向大的集合进行转移:如图所示,我们只能从当前的状态向左一个,或下一个方向进行转移,这里的限制条件就是前一行的人数要比下一行的人数大我们才能进行状态的转移。
    在这里插入图片描述
  2. 我们遍历每一种状态来进行不同状态转移的加和

ACcode:

/*
 * @Author: NEFU_马家沟老三
 * @LastEditTime: 2020-10-01 20:46:41
 * @CSDN blog: https://blog.csdn.net/acm_durante
 * @E-mail: 1055323152@qq.com
 * @ProbTitle: 
 */
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define lowbit(x) ((x) & -(x))
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#define mem(a, b) memset(a, b, sizeof(a))
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const double PI = acos(-1.0);
ll dp[31][31][31][31][31];
int s[5];
int main()
{
    int k;
    while(~scanf("%d",&k) && k){
        rep(i,1,k) scanf("%d",&s[i]);
        rep(i,k+1,5) s[i] = 0;
        mem(dp,0);
        dp[0][0][0][0][0] = 1;
        rep(a,0,s[1]) rep(b,0,min(s[2],a)) rep(c,0,min(s[3],b)) rep(d,0,min(s[4],c)) rep(e,0,min(s[5],d)){//这里min是指前一行比上一行的人数要多
            if(a && a > b) dp[a][b][c][d][e] += dp[a - 1][b][c][d][e];//要想当前行转移的行的值不能为0,并且前一行要比上一行人数多才能进行填充人数
            if(b && b > c) dp[a][b][c][d][e] += dp[a][b - 1][c][d][e];
            if(c && c > d) dp[a][b][c][d][e] += dp[a][b][c - 1][d][e];
            if(d && d > e) dp[a][b][c][d][e] += dp[a][b][c][d - 1][e];
            if(e) dp[a][b][c][d][e] += dp[a][b][c][d][e - 1];
        }
        printf("%lld\n",dp[s[1]][s[2]][s[3]][s[4]][s[5]]);
    }
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值