Arrange the Bulls POJ - 2441

原题链接

考察:状压dp

POJ 3254的延伸题

思路:

       讲牛的需求看成看成肥沃的土地,也就是把谷仓看成一个矩阵.与牛的需求相符的位置可以养牛.这样就变成了POJ 3254差不多的题.f[i,j]表示前i头牛谷仓的养殖情况.状态转移方程是f[i][j] += f[i-1][k].

       这道题直接枚举i、j、k有超时的危险,我们可以把j、k一个换成m,另一个则是1<<m.这两个哪个循环在外面也可以优化.

注意:用滚动数组要清零.j循环在内方便数组清零

再再注意:这道题的f[i-1&1][j]保证了是need[i-1]允许的情况,而下面的!(j>>k&1)保证上下两行不会在同一列.(need[i]>>k&1)保证了算的情况是need[i]符合的.

 

 1 #include <iostream>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <cstdio>
 5 using namespace std;
 6 const int N = 20;
 7 int need[N],f[2][1<<N];
 8 int main()
 9 {
10     int n,m,ans = 0;
11     scanf("%d%d",&n,&m);
12     for(int i=0;i<n;i++)
13     {
14         int p; scanf("%d",&p);
15         for(int j=1;j<=p;j++)
16         {
17             int x; scanf("%d",&x);
18             need[i]|=(1<<(x-1));
19         }
20     }
21     for(int i=0;i<m;i++) if(need[0]>>i&1) f[0&1][1<<i] = 1;
22     for(int i=1;i<n;i++)
23       for(int j=0;j<1<<m;j++)  
24         if(f[i-1&1][j])//保证是i-1有的 
25         {
26             for(int k=0;k<m;k++)
27               if(!(j>>k&1)&&(need[i]>>k&1))//保证是need[i]没有的 
28                   f[i&1][j|(1<<k)] += f[i-1&1][j];
29                f[i-1&1][j] = 0;
30         }    
31     for(int i=1;i<1<<m;i++) ans+=f[n-1&1][i];
32     printf("%d\n",ans);
33     return 0;
34 }

 

2021.3.16 二刷 写了个压缩为1维的做法,类似01背包的压缩

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <vector>
 5 using namespace std;
 6 const int N = 21,M = 20; 
 7 int n,m,mp[N],f[1<<M],ans;
 8 int main() 
 9 {
10     scanf("%d%d",&n,&m);
11     for(int i=1;i<=n;i++)
12     {
13         int x;
14         scanf("%d",&x);
15         while(x--)
16         {
17             int a; scanf("%d",&a);
18             mp[i]|=1<<(a-1);
19         }
20     }
21     f[0] = 1;
22     for(int i=1;i<=n;i++)
23       for(int j=1<<m;j>=0;j--)
24       {
25           if(f[j])
26            for(int k=0;k<m;k++)
27            if(!(j>>k&1)&&(mp[i]>>k&1))
28            {
29                f[j|(1<<k)] += f[j];
30            } 
31         f[j] = 0;
32       }
33     for(int i=0;i<1<<m;i++) ans+=f[i];
34     printf("%d\n",ans);
35     return 0;
36 } 
一维压缩

 

posted @ 2021-02-14 22:12  acmloser  阅读(75)  评论(0编辑  收藏  举报