http://acm.timus.ru/problem.aspx?space=1&num=1526ios
題目大意:spa
能夠從n個碟子中任選一個放在桌子上(不斷往上放),也能夠把桌子上最頂端的盤子拿走blog
對於約束條件 i , j 是說假如 i 這個碟子還在桌子上,就不能拿走 j 這個碟子,也就等於放了遞歸
i 這個碟子就不能再放 j 了,由於放了 i 再放 j,就會相互約束,沒法拿走碟子了。隊列
思路:get
能夠把問題轉化爲括號匹配隊列問題,左括號表明拿來碟子,右括號表明拿走碟子。string
dp[x][y] , x 表明還有x個碟子能夠放,y 表明已經放了的碟子的狀態壓縮表示it
再放的形式就是 「 ( 遞歸1 ) 遞歸2 」,根據y能夠斷定哪些括號能夠放,枚舉能夠放的括號io
括號肯定後還要 枚舉 「遞歸1」 的括號數量(偶數),對應的y須要更新,在 「遞歸1」 括號數量肯定的狀況下class
「遞歸2」 的括號數量也肯定了,對於「遞歸2」 y 不須要更新
代碼:
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<vector> using namespace std; const int N=205; const int M=(1<<10); int dp[N][M]; int p,t,n,m; vector<int>unlike[N]; int put[M][11]; int fput(int y,int i) { if(put[y][i]!=-1) return put[y][i]; for(unsigned int j=0;j<unlike[i].size();++j) { int k=unlike[i][j]; if((y&(1<<k))>0) return (put[y][i]=0); } return (put[y][i]=1); } int dfs(int x,int y) { if(dp[x][y]!=-1) return dp[x][y]; if(x==0) return (dp[x][y]=1); dp[x][y]=0; for(int i=0;i<n;++i) if(fput(y,i)==1) { for(int j=0;j+2<=x;j+=2) { dp[x][y]+=(dfs(j,y|(1<<i))*dfs(x-2-j,y)); dp[x][y]%=p; } } return dp[x][y]; } int main() { //freopen("data.in","r",stdin); scanf("%d %d %d %d",&p,&t,&n,&m); while(m--) { int i,j; scanf("%d %d",&i,&j); --i;--j; unlike[j].push_back(i); } memset(dp,-1,sizeof(dp)); memset(put,-1,sizeof(put)); printf("%d\n",dfs(t,0)); return 0; }