《演算法競賽進階指南》0x51線性DP 照相館排列
阿新 • • 發佈:2020-07-25
題目連結:https://www.acwing.com/problem/content/273/
題目要求將N個人排成不超過五列,每列的人數限制而且遞減,現在要求每行每列都是遞減的方案的數量,通過狀態集合以及轉移規律,f[a][b][c][d][e]滿足索引遞減的性質 ,在轉移的時候要維護這個性質,所以除了e以為的所有的索引-1情況都需要考慮,e-1的情況自然維護了這個性質。此外,從高到低排這些人,當前要排的人排在哪一行就是決策的劃分過程,當前決策中的方案數量等價於之前階段的某一個決策的方案數,所以直接累加轉移的方案即可。
在DP問題中,集合和集合劃分的概念十分重要,本問題中的集合上的屬性是數量。
程式碼:
#include<iostream> #include<cstdio> #include<string.h> using namespace std; const int maxn = 31; typedef long long ll; ll f[maxn][maxn][maxn][maxn][maxn]; int n; int main(){ while(scanf("%d",&n) && n){ int s[5]={0}; for(int i=0;i<n;i++)cin>>s[i]; memset(f,0,sizeof(f)); f[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(c,s[3]);d++) for(int e=0;e<=min(s[4],d);e++) {// f[a][b][c][d][e]滿足索引遞減的性質 ll& v=f[a][b][c][d][e]; if(a && a>b)v+=f[a-1][b][c][d][e]; if(b && b>c)v+=f[a][b-1][c][d][e]; if(c && c>d)v+=f[a][b][c-1][d][e]; if(d && d>e)v+=f[a][b][c][d-1][e]; if(e)v+=f[a][b][c][d][e-1]; } printf("%lld\n",f[s[0]][s[1]][s[2]][s[3]][s[4]]); } }