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 }
View Code

 

posted @ 2015-04-06 12:57  fukan  阅读(177)  评论(0编辑  收藏  举报