poj3254 状态压缩dp

花了一个晚上看别人的代码然后才明白题的思路啊!!!然后写的时候一个劲的WA,然后才发现竟然什么也不中也是一种方案,自己给自己写的数据自己算出来的结果都是错的啊!!!!

题意:给出一个n*m的方格,每个方格可以种草也可以不中,但是种草的方格是不能相邻的,让求最多有多少种方案满足题意!!

解题思路:状态dp,采用二进制的数据表示每个方格种还是不种,然后化为十进制记录不同的状态,dp[n][m]代表第n行的第m中状态一个出现的方案个数,对于m的状态,要判断是否可以存在,并且是否有两个草地相邻,是否和第n-1行的的某种状态的草地相邻,如果相邻的话就舍弃!

然后就是求最后状态的所有之和了,千万不要写出来题了就很高兴而忘记模100000000了!今天中午木睡觉,现在太困了,睡觉去啦!

#include<iostream>
#include<cstdio>
#include<string>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<climits>
using namespace std; 
#define rep(i,n) for(i=0; i<(n); i++)
#define reph(i,n,m) for(i=(n); i<=(m); i++)//正循环的
#define repd(i,n,m) for(i=(n); i>=(m); i--) //负循环的 
#define fab(a) (a)>0?(a):0-(a)
#define ll long long
#define arc(a) (a)*(a)
#define inf 100000000   //最大值的
#define exp 0.0000001     //浮点型的
#define N    15 //记录开的数组
int dp[N][1<<N];//i行的第j状态时的方法数 
int f[N],n,m;
bool panduan(int a,int b)//a为i所表示的,b为j所表示的
{
     if((f[a] & b)!=b)//说明这种状态是不存在的 
      return false; 
     int x=3;
     int i;
     reph(i,1,m-1)
     {
          if((b & x)==x)//说明有连着的状态存在 
           return false;
          x=x<<1;
     }
    return true;
 } 
int main()
{
    int i,j,s;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
         reph(i,1,n)
         {
                    f[i]=0;
                    reph(j,1,m)
                    {
                               scanf("%d",&s);//对于移位操作要加括号,优先级实在是分不清啊!!!1 
                               f[i]=(f[i]<<1)+s;//记录的是输入的状态的    
                    }
         }
         int r=1<<m;
         memset(dp,0,sizeof(dp));
       //  reph(i,0,r-1)
          dp[0][0]=1;//这样的赋值使得第一行的可以用的状态就是一次啦 
         reph(i,1,n)
         {
                    reph(j,0,r-1)
                    {
                               if(panduan(i,j))
                               {
                                        int k;
                                        reph(k,0,r-1)       
                                         if((k & j)==0)//是没有可以挨着的 
                                          dp[i][j]=(dp[i][j]+dp[i-1][k])%inf;
                               }
//							   printf("%d ",dp[i][j]);
                    }
         }
         int ans=0;
         reph(i,0,r-1)
          ans=(ans+dp[n][i])%inf;
          printf("%d\n",ans);
    }
    return 0;
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

淡定的小Y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值