POJ 2441 Arrange the Bulls(状态压缩DP)

题意很简单,n头牛,m个位置,每头牛有各自喜欢的位置,问安排这n头牛使得每头牛都在各自喜欢的位置有几种安排方法。

2000MS代码:

#include <cstdio>
#include <cstring>
int dp[(1<<20)+2];
int one[(1 << 20) + 2];
//用来数出状态为i时1的个数,具体到这个题中就是
//状态为i时有多少头牛已经安排好牛棚
void CountOne(int m)
{
    for(int i=0; i< (1 << m); ++i)
    {
        int num=0;
        for(int j=0; j< m; ++j)
        {
            if( (i & (1 << j)) != 0)//i的第j位置是否为一
                ++num;
        }
        one[i] = num;
    }
}
int main()
{
//    freopen("in.cpp","r",stdin);
    int n,m;
    scanf("%d%d",&n,&m);
    CountOne(m);
    memset(dp,0,sizeof(dp));
    dp[0] = 1; //一头牛都没有安排,状态为0的满足条件的方案数为1
    for(int i=1; i<=n; ++i)
    {
        int cnt; //每头牛喜欢住的牛棚数
        scanf("%d",&cnt);
        while(cnt--)
        {
            int k; //该牛棚编号
            scanf("%d",&k);
            --k;//使得牛棚编号为 0 ~ m-1
            for(int j=0; j< (1 << m); ++j)
            {
                if((j & (1 << k)) != 0 && one[j] == i) //这个状态已经安排好了i头牛,且第k个牛棚安排的是第i头牛
                    dp[j] += dp[j-(1<<k)];
            }
        }
    }
    // 最终结果为安排了n头牛的状态满足条件的方案数的总和
    int ans=0;
    for(int j=0; j< (1 << m ); ++j)
    {
        if(one[j] == n)
        {
            ans += dp[j];
        }
    }
    printf("%d\n",ans);
    return 0;
}
View Code

90MS

#include <stdio.h>
#include <string.h>

int map[25][25];
int now[(1<<20)+5];

int main()
{
    int i,j,n,m,k,x,p,ret;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(map,0,sizeof(map));
        for (i=0;i<n;i++)
        {
            scanf("%d",&k);
            while(k--)
            {
                scanf("%d",&x);
                x--;//0~m-1编号
                map[i+1][x]=1;
            }
        }
        if (n>m)
        {
            printf("0\n");
            continue;
        }
        memset(now,0,sizeof(now));
        now[0]=1;
        for (i=0;i<n;i++)
        {
            for (j=(1<<m)-1;j>=0;j--)
            {
                if (now[j]==0) continue;
                for (k=0;k<m;k++)
                {
                    if ((j & (1<<k))!=0) continue;//判断j的第k的位置为1
                    if (map[i+1][k]==0) continue;//在k的棚没有位置
                    p=(j | (1<<k));//j的第k的位置变1
                    now[p]+=now[j];
                }
                now[j]=0;
            }
        }
        ret=0;
        for (i=0;i<(1<<m);i++)
        {
            ret+=now[i];
        }
        printf("%d\n",ret);
    }
    return 0;
}
View Code

 

posted @ 2018-06-05 18:25  shuai_hui  阅读(148)  评论(0编辑  收藏  举报