状态压缩DP入门题

.

 1 /*本题为状态压缩题
 2 题目大意 :
 3   一个矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧,
 4   可以放牧用1表示,否则用0表示,在这块牧场放牛,要求两个相邻的方
 5   格不能同时放牛(不包括斜着的),即牛与牛不能相邻。问有多少种放牛方
 6   案(一头牛都不放也是一种方案); 
 7 要枚举每一行中的是否种植(也就是0 1状态) 最大状态的12,
 8 每一行的总共可以有的种植方式就有2^12次方种,
 9 而二进制的0 1 特征刚好可以表示这些种植方式;
10 比如0001 表示在第四个位置种植,其他不种;
11 比如0101 表示2 4种,依此类推。。。
12 所以dp[n][m]的第二维度的大小,就要根据题目中的最大限度,
13 本题n,m的大小开到了12;所以我们以13为上限,或者2^12+10都可以;
14 dp[n][1<<13];
15 */
16 #include<cstdio>
17 #include<string.h>
18 using namespace std;
19 const int mod=1e8;
20 const int maxn=1<<13;
21 int a[maxn];
22 int dp[13][maxn];
23 int mp[13];
24 int judge1(int x)   //判断同一行中是否会出现相邻为1的情况。
25 {
26     return (x&(x<<1));
27 }
28 int judge2(int i,int x) //判断此情况是否是题目中的可列举情况;
29 {                       //因为题目中有限制哪些地方可以种植,哪些不可以;
30     return (mp[i]&a[x]);
31 }
32 void init() //初始化
33 {
34     memset(dp,0,sizeof(dp));
35     memset(mp,0,sizeof(mp));
36     memset(a,0,sizeof(a));
37 }
38 int main()
39 {
40     int n,m;
41     while(scanf("%d%d",&n,&m)!=EOF){
42         init();
43         for(int i=1;i<=n;i++)
44         for(int j=1;j<=m;j++){
45             int t;
46             scanf("%d",&t);
47             if(t==0)
48                 mp[i]+=1<<(j-1); //将题目中每一行的限制情况存储起来;
49                                  //这里存储的是不可种植的地方
50                                  //后面的判断某种种植方式是否可行的方案
51                                  //就可以通过mp[i]&a[x]来解决;
52                                  //比如题目中限制了0 1 0 1,表示只有2 4可种植
53                                  //而这里是存储了1 0 1 0,现在有个方案是0 1 0 0 
54                                  //将其与1 0 1 0进行&运行,假如等于0,就表示可行;
55         }
56         int cot=0;
57         for(int i=0;i<(1<<m);i++){
58             if(!judge1(i))
59                 a[cot++]=i;  //将第一行可表示的状态(没有相邻1)列举出来
60                              //此时还未与题目中的限制的可种植地方相比较;    
61         }
62         for(int i=0;i<cot;i++) //与题目限制的相比较;
63             if(!judge2(1,i))   //如果方案可行,=1;
64                 dp[1][i]=1;   
65         for(int i=2;i<=n;i++){
66             for(int j=0;j<cot;j++){
67                 if(judge2(i,j)) //如果不满足限制的种植条件
68                     continue;
69                 for(int k=0;k<cot;k++){
70                     if(judge2(i-1,k)) //如果不满足限制的种植条件
71                         continue;
72                     if(!(a[k]&a[j]))
73                         dp[i][j]+=dp[i-1][k];
74                 }
75             }
76         }
77         int ans=0;
78         for(int i=0;i<cot;i++){
79             ans+=dp[n][i];   //将所有方案相加;
80             ans%=mod;
81         }
82         printf("%d\n",ans);
83     }
84     return 0;
85 }

 

posted @ 2019-11-18 21:25  古比  阅读(284)  评论(0编辑  收藏  举报