poj 3254

来源:互联网 发布:公需课挂机软件 编辑:程序博客网 时间:2024/06/06 19:34

题目:

题意:
有n*m大的一个地方,1表示土地肥沃可以种植物,0表示不能种植物,问:在不许有两个植物相邻的情况下,有多少种放置的方法。
分析:直接dp因为状态较多,数组很难直接表示出来,我们采用二进制状态压缩的方法来解决问题。

分析:
第一道 状压dp 题哦!

所以先做好准备工作:–位运算 tata~ 我自己整理了一丢丢
& 与 同为1为1 or 为0

| 或 同0为0 or 为1

^ 异或 不同为1 相同为0

~ 取反 去相反的

左移 << 右边空出的位上补0,左边的位将从字头挤掉,其值相当于乘2。

右移 同理

那么来说这道题,

我们用dp【i】【j】表示第i行的j的状态。
那么如果满足条件的话,dp【i】【j】+=sum(dp【i】【j】)

所以,我们还需要 判断 。
判断有两个条件:
第一是:
在能放的地方放。

那么我们将 土地的情况和我当前的枚举情况 进行一下 & 的运算 如果等于我的枚举情况,就可以放。
举个例子:
1 1 1 那么 其中一种可以放置的情况 就是 11 0
1 1 1
&1 1 0
1 1 0
再举个返利:
1 0 0 不能放置的 011
1 0 0
&0 1 1
0 0 0 不合法呀~

第二是:

相邻的地方不能 放置啊 这个就很好说了 如果你把当前状态左移一位,在和原来比较的 就是相邻位置 的情况啦 同样是 & 运算。 如果不是0 就不可以放。

至此,这道题最关键的地方就讲完了。

另外还有一步把输进的 转化为 10 进制。。。

下面看代码就好了【【【其实还没写,,现在去写、、、、

#include<cstdio>#include<algorithm>#include<cstring>using namespace std;//by mars_chint n,m,ans;int state[13];int dp[13][1<<13];   //dp[i][j]表示第i行的j状态,要枚举状态 bool judge(int x,int y){    if((state[x] & y)!=y) return 0;    //这是不能放置的,为什么看上边的解释啦    if((y&(y<<1))!= 0) return 0;       //  相邻的是不可以的    else return 1;  } int main(){    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++)    {        state[i]=0;        for(int j=1;j<=m;j++)        {            int k;            scanf("%d",&k);            state[i]=(state[i]<<1)+k;       // 把每一行都转成十进制数   eg 111 -> 7         }    }    memset(dp,0,sizeof(dp));    dp[0][0]=1;    for(int i=1;i<=n;i++)    {        for(int j=0;j<=(1<<m);j++)        {            if(judge(i,j) == 0) continue;            for(int k=0;k<=(1<<m);k++)            {                if(((j & k)!=0))continue;                dp[i][j]+=dp[i-1][k];     //第i-1行  不能和第i行  相邻的。                 dp[i][j]%=100000000;                      }        }    }    for(int i=0;i<=(1<<m);i++)    {        ans+=dp[n][i];        ans%=100000000;    }    printf("%d\n",ans);    return 0;}
0 0