AcWing 271. 杨老师的照相排列

题解都在代码里了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ld,ld> pdd;
const ld PI=acos(-1);
const ld eps=1e-9;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const int seed=131;
const int M = 1e5+7;
ll dp[31][31][31][31][31];
/*i排安排ai,的方案数 
		必须满足a1>=a2>=a3>=a4>=a5  才有解 
状态转移 :	        dp[a1][a2][a3][a4][a5] -> dp[a1+1][a2][a3][a4][a5]+=dp[a1][a2][a3][a4][a5]
	    	a2<a1   dp[a1][a2][a3][a4][a5] -> dp[a1][a2+1][a3][a4][a5]+=dp[a1][a2][a3][a4][a5]
	    	a3<a2   dp[a1][a2][a3][a4][a5] -> dp[a1][a2][a3+1][a4][a5]+=dp[a1][a2][a3][a4][a5]
	    	a4<a3   dp[a1][a2][a3][a4][a5] -> dp[a1][a2][a3][a4+1][a5]+=dp[a1][a2][a3][a4][a5]
	    	a5<a4   dp[a1][a2][a3][a4][a5] -> dp[a1][a2][a3][a4][a5+1]+=dp[a1][a2][a3][a4][a5]
	本题可以通过状态转移后面的状态,或者计算一个状态怎么由前面状态转移2种方法
	我写的是前面一种方法,后面的方法是比较常规的方法 
	
	从第一排开始往后安排学生,保证到一个状态时,它的状态已经转移完毕 ,且每个状态只跑一次 
	状态转移就像DAG一样,跑到一个点时,必须 保证所有连向当前点的点已经把状态转移到了当前点,
	然后它再把状态转移给连向的点。
	
	如果是后面一种方法,则必须保证,跑到一个点的时候,能到达当前点的 点 的状态已经全部更新。 
	
	初始dp[0][0][0][0][0]=1,其余为0;//因为全部由这个状态开始转移
	
*/ 
int s[6];
int main()
{
	/*ios::sync_with_stdio(false);
    	cin.tie(0);*/
    int k;
    while(cin>>k&&k){
    	memset(dp,0,sizeof(dp));//初始化 
    	memset(s,0,sizeof(s));
    	for(int i=1;i<=k;i++)
		cin>>s[i];
		dp[0][0][0][0][0]=1;
		for(int a1=0;a1<=s[1];a1++)
		for(int a2=0;a2<=s[2];a2++)
		for(int a3=0;a3<=s[1];a3++)
		for(int a4=0;a4<=s[4];a4++)
		for(int a5=0;a5<=s[5];a5++){
			if(a1<s[1])dp[a1+1][a2][a3][a4][a5]+=dp[a1][a2][a3][a4][a5];
			if(a2<a1&&a2<s[2])dp[a1][a2+1][a3][a4][a5]+=dp[a1][a2][a3][a4][a5];
			if(a3<a2&&a3<s[3])dp[a1][a2][a3+1][a4][a5]+=dp[a1][a2][a3][a4][a5];
			if(a4<a3&&a4<s[4])dp[a1][a2][a3][a4+1][a5]+=dp[a1][a2][a3][a4][a5];
			if(a5<a4&&a5<s[5])dp[a1][a2][a3][a4][a5+1]+=dp[a1][a2][a3][a4][a5];
		}
		cout<<dp[s[1]][s[2]][s[3]][s[4]][s[5]]<<endl;	 
	}
  	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值