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 @   acmloser  阅读(77)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
点击右上角即可分享
微信分享提示