poj 3254 状压dp

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

链接:点我

定义状态dp【i】【j】,第 i 行状态为 j 的时候放牛的种数。

去年暑假做过的题,现在忘光了

 1 #include <cstdio>

 2 #include <cstring>

 3 const int N = 13;

 4 const int M = 1<<N;

 5 const int mod = 100000000;

 6 int st[M],map[M];  //分别存每一行的状态和给出地的状态

 7 int dp[N][M];  //表示在第i行状态为j时候可以放牛的种数

 8 bool judge1(int x)  //判断二进制有没有相邻的1

 9 {

10     return (x&(x<<1));

11 }

12 bool judge2(int i,int x)

13 {

14     return (map[i]&st[x]);

15 }

16 int main()

17 {

18     int n,m,x;

19     while(~scanf("%d%d",&n,&m))

20     {

21         memset(st,0,sizeof(st));

22         memset(map,0,sizeof(map));

23         memset(dp,0,sizeof(dp));

24         for(int i=1;i<=n;i++)

25         {

26             for(int j=1;j<=m;j++){

27                 scanf("%d",&x);

28                 if(x==0)

29                     map[i]+=(1<<(j-1));

30             }

31 

32         }

33         int k=0;

34         for(int i=0;i<(1<<m);i++){

35             if(!judge1(i))

36                 st[k++]=i;

37         }

38         for(int i=0;i<k;i++)

39         {

40             if(!judge2(1,i))

41                 dp[1][i]=1;

42         }

43         for(int i=2;i<=n;i++)

44         {

45             for(int j=0;j<k;j++)

46             {

47                 if(judge2(i,j))  //判断第i行 假如按状态j放牛的话行不行。

48                     continue;

49                 for(int f=0;f<k;f++)    //上一行的状态

50                 {

51                     if(judge2(i-1,f))   //剪枝 判断上一行与其状态是否满足

52                         continue;

53                     if(!(st[j]&st[f]))

54                         dp[i][j]+=dp[i-1][f];

55                 }

56             }

57         }

58         int ans=0;

59         for(int i=0;i<k;i++){

60             ans+=dp[n][i];

61             ans%=mod;

62         }

63         printf("%d\n",ans);

64     }

65     return 0;

66 }

 

你可能感兴趣的:(poj)