【状压dp】poj 2441 Arrange the Bulls

版权声明:转载标注来源喔~ https://blog.csdn.net/iroy33/article/details/89892865

题意: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)
            {
                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();

}

猜你喜欢

转载自blog.csdn.net/iroy33/article/details/89892865
今日推荐