poj 2441 Arrange the Bulls (状态压缩dp+滚动数组)
题意:
n头牛和m个barn,每头牛有自己喜欢的p个barn(1<=p<=m),问有多少种安排n头牛的方法。
分析:
dp[i][j]表示i头牛在j状态下的方法数。
dp[i][j] = sigma(dp[i-1][k]) (k从0到 1<<m)。
要用滚动数组优化,否则dp[20][1<<20]会MLE!
注意滚动数组的清空= =!
1 #include<stdio.h> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cstdlib> 6 #include<cmath> 7 #include<vector> 8 #include<queue> 9 #include<map> 10 #include<set> 11 12 using namespace std; 13 14 typedef long long ll; 15 16 vector<int> p[25]; 17 int dp[2][1<<20],n; 18 19 int main() 20 { 21 int m,x,y; 22 while(~scanf("%d%d",&n,&m)) 23 { 24 for(int i=1;i<=n;i++) 25 { 26 p[i].clear(); 27 scanf("%d",&x); 28 while(x--) 29 { 30 scanf("%d",&y); 31 p[i].push_back(y); 32 } 33 } 34 memset(dp,0,sizeof(dp)); 35 36 int all = (1<<m)-1; 37 dp[0][0] = 1; 38 int t; 39 40 for(int i=1;i<=n;i++) 41 { 42 for(int k=0;k<=all;k++) //每种状态访问一次 43 { 44 if(!dp[(i-1)&1][k]) continue; //只有前i-1头牛的k状态有值的情况下才能确定第i头牛的放法 45 for(int j=0;j<p[i].size();j++) 46 { 47 t = p[i][j]-1; 48 if((k>>t)&1) continue; //如果k状态下这个位置已经有牛则不能放 49 dp[i&1][k|(1<<t)] += dp[(i-1)&1][k]; 50 } 51 } 52 memset(dp[(i-1)&1],0,sizeof(dp[(i-1)&1])); //清空滚动数组下次要用的一维 53 } 54 55 int ans = 0; 56 for(int i=1;i<=all;i++) 57 { 58 ans+=dp[n&1][i]; 59 } 60 printf("%d\n",ans); 61 } 62 return 0; 63 }