http://acm.timus.ru/problem.aspx?space=1&num=1526
题目大意:
可以从n个碟子中任选一个放在桌子上(不断往上放),也可以把桌子上最顶端的盘子拿走
对于约束条件 i , j 是说假如 i 这个碟子还在桌子上,就不能拿走 j 这个碟子,也就等于放了
i 这个碟子就不能再放 j 了,因为放了 i 再放 j,就会相互约束,无法拿走碟子了。
思路:
可以把问题转化为括号匹配队列问题,左括号代表拿来碟子,右括号代表拿走碟子。
dp[x][y] , x 代表还有x个碟子可以放,y 代表已经放了的碟子的状态压缩表示
再放的形式就是 “ ( 递归1 ) 递归2 ”,根据y可以判定哪些括号可以放,枚举可以放的括号
括号确定后还要 枚举 “递归1” 的括号数量(偶数),对应的y需要更新,在 “递归1” 括号数量确定的情况下
“递归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; }