【状压dp】poj 2441 Arrange the Bulls

题意:n头牛m个牛栏,每个牛栏只能有一头牛,每头牛只能被放在自己喜欢的牛栏里,问有多少种方法

思路:一开始想开dp[1<<n][1<<m]来标记,发现开不下思路就端了orz

参考博客

_builtin_popcount()计算二进制中多少个1,采用的是查表的方法

说到底,这个函数到底有什么实际用处呢?当然有了,使用一个二进制数字表示一个集合的时候,枚举一个组合(子集),需要判断这个数字里面的 1 的个数是不是和子集的大小相等。这种方法通常是属于暴力法,如果不是使用二进制数字表示集合,很可能就计算超时了。

https://blog.csdn.net/gaochao1900/article/details/5646211

状态代表每个牛棚是否用过,按顺序安置牛

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int INF=0x3f3f3f3f;
int dp[1<<21];
int mp[25][25];
int n,m;

//1<<20 1e6
void solve()
{
    dp[0]=1;
    for(int i=0;i<n;++i)                    //按顺序安置牛
    {
        for(int j=0;j<(1<<m);++j)            //枚举所有状态
        {
            if(__builtin_popcount(j)==i)     //考虑第i头牛的时候,前面i头牛已经访问过了,这样才能进行下面的转移(状态是一点点加上去der),另一种更直观的表示是dp[j]!=0 
            {
                for(int k=0;k<m;++k)        
                {
                    if(!(j&(1<<k))&&mp[i][k])   //k栏还是空的并且牛i喜欢k
                    {
                        dp[j|(1<<k)]+=dp[j];    //安排上的栏数由少变多,所以状态0~(1<<m)-1

                    }
                }
            }
        }
    }
    int ans=0;
    for(int i=0;i<(1<<m);++i)
        if(__builtin_popcount(i)==n)
            ans+=dp[i];
    cout<<ans<<endl;
}
int main()
{
    cin>>n>>m;
    for(int i=0;i<n;++i)
    {
        int num;
        cin>>num;
        for(int j=0;j<num;++j)
        {
            int x;
            cin>>x;
            mp[i][x-1]=1;           //这样的话第xxx个牛栏对应的二进制位就是1<<xxx
        }
    }
    solve();

}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值