状态压缩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 }