poj3254 Corn Fields (状态压缩)

http://poj.org/problem?id=3254


题意:

给出一个n行m列的草地,1表示肥沃,0表示贫瘠,现在要把一些牛放在肥沃的草地上,但是要求所有牛不能相邻,问你有多少种放法。


思路:首先用s[]数组将1<<12 内的所有整数的二进制形式时没有相邻的1的这样的数存放进去;(用的时候方便)
然后用state数组把草地的状态的二进制的反码整数存进去 如0 1 0 则为5
然后先把第一行的可以的状态用a[i]存起来(a[i]为1则表示i整数的二进制可以适合第一行,0则不适合)
然后用三层for循环,
第一层从第一行遍历到最后一行用i带便第几行
第二次从第1中状态(整数的二进制)遍历到最后一种状态此时判断第j种状态是否适合于第i行
第三层for 如果第二层里判断出第j种状态适合于第i行,则此for为判断这个第j种情况与上一行的第k种情况是否冲突(直接再把第j种与所有的状态即s数组比较一遍,不冲突的则加上上一行的不冲突的这种情况的所有情况 即使累积的a[i]数组。
然后第二层for外第一层for里将 a【i】更新即是到目前为止第i种状态可以用的次数
a[i]的意义好比不同颜色的小球,把他们排列,并且要求相邻小球不能同颜色,那么只要i个小球和第i-1个小球不一样颜色即可,那么每次确定第i个小球一个颜色可行,即把之前的所有情况加起来极为第i个位这个颜色的时候所有的情况,然后第i个再为下一个颜色的时候又是一组情况,再加起来,最后把最后一个小球的没个可以的颜色从而产生的那一组小球的总和加起来的总和即为 所有的可能组合

#include<cstdio>
#include<iostream>
using namespace std;
#define N 1<<12
#define MOD 100000000
int main()
{
   int state[12],i,j,k,s[N],a[N],b[N],num,m,n,x,ans;
   for(num=i=0;i<N;i++)
   {
       if( (i&(i<<1))==0)
           s[num++]=i;
   }
   while(scanf("%d %d",&m,&n)==2)
   {
    for(i=0;i<m;i++)
   {
       state[i]=0;
       for(j=0;j<n;j++)
       {
           scanf("%d",&x);
           state[i]=(state[i]<<1)+1-x;
       }
   }
   x=1<<n;
   for(i=0;s[i]<x;i++)
   {
       if( s[i]&state[0] )
           a[i]=0;
       else
           a[i]=1;
   }
   for(i=1;i<m;i++)
   {
       for(j=0;s[j]<x;j++)
       {
           b[j]=0;
           if(!(s[j]&state[i]))
               for(k=0;s[k]<x;k++)
               {
                   if(!(s[j]&s[k]))
                   {
                       b[j]=(b[j]+a[k])%MOD;
                   }
               }
       }
       for(j=0;s[j]<x;j++)
           a[j]=b[j];
   }
   for(ans=i=0;s[i]<x;i++)
       ans=(ans+a[i])%MOD;
   printf("%d\n",ans);
}
   return 0;
}


 
点击打开链接 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值