题目大意:
输入n m
接下来n行m列
0表示不能种玉米 1表示能
要求种玉米位置的上下左右四连通区域不能种玉米
输出方案数
Sample Input
2 3
1 1 1
0 1 0
Sample Output
9
Hint
Number the squares as follows:
1 2 3
4
There are four ways to plant only on one squares (1, 2, 3, or 4), three ways to plant on two squares (13, 14, or 34), 1 way to plant on three squares (134), and one way to plant on no squares. 4+3+1+1=9.
#include <bits/stdc++.h> #define MOD 100000000 using namespace std; int mir[13],may[1<<12],dp[13][1<<12]; int main() { int n,m; while(~scanf("%d%d",&n,&m)) { int num=0; for(int i=0;i<(1<<m);i++) if((i&(i<<1))==0) may[num++]=i; /// 等于0说明符合条件 may[]保存所有可能放置 /// 左移一位后,若不为0,说明有相邻两位同时为1 /// 如 i 为011,则 i<<1 为110,(011&110) = 1 memset(mir,0,sizeof(mir)); for(int i=0;i<n;i++) for(int j=0;j<m;j++) { int tmp; scanf("%d",&tmp); if(tmp==0) mir[i]|=1<<j; /// mir[]可理解为 i 行的镜像拓本 } memset(dp,0,sizeof(dp)); for(int i=0;i<num;i++)/// 枚举所有可能 判断与拓本是否可匹配 if((mir[0]&may[i])==0) dp[0][may[i]]=1; /// 等于0说明may[i]为该行的可能放置 for(int i=0;i<n-1;i++) // 枚举各行 从本行推下一行 所以只需到n-1行 for(int j=0;j<num;j++) // 枚举所有可能放置 if((mir[i]&may[j])==0)/// 当与本行可匹配时 { // 该放置是本行可能出现的符合条件的放置时 for(int k=0;k<num;k++)// 枚举所有可能(下一行的) if(((mir[i+1]&may[k])==0)&&((may[k]&may[j])==0)) /// 该放置为下一行的可能放置(与下一行的拓本可匹配) /// 且 与本行的放置可匹配时 dp[i+1][may[k]]+=dp[i][may[j]]; } int ans=0; for(int i=0;i<num;i++)// 枚举所有可能放置(最后一行) ans=ans+dp[n-1][may[i]],ans%=MOD; // 由前往后推 所以只要最后一行存在这种放置的方案 // 则表示这种方案也符合前面所有行的放置 printf("%d ",ans); } return 0; }