思路
因为题目的数据很小,所以直接二进制枚举就好了。
思路就是枚举每一行的二进制形式,1表示有人,0表示没人,dp[i][[j]表示第i行的放置状态是j
下面考虑下判断操作是否合法:
1、首先上一层 放了人的地方下一层必须不放,既上一层第 i位位1,下一层第i位必须为0,上一层第 i 位为0下一层可放可不放 , 这个操作可以用 & 运算符 j & k ,j表示上一层的状态,k表示这一层 ,当j & k 为 0 时说明这一层放置方法为k合理
2、本层Map[i] 的第j位为0表示这层不能放人,假设放置方法为 k ,则 (Map[i] & k) == k 表示操作合法(Map[i]的第j位为0如果k的第j位为0 用 & 后结果不等于 k
3、本层不能有连续的1存在,,所以用 j & (j >> 1)若不为0表示存在连续的 1
代码
#pragma GCC target("avx,sse2,sse3,sse4,popcnt") #pragma GCC optimize("O2,O3,Ofast,inline,unroll-all-loops,-ffast-math") #include<bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; #define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0) #define pb push_back #define pll pair<ll,ll> #define INF 0x3f3f3f3f const int mod = 100000000; const int maxn = 100005; #define stop system("pause") inline ll read(){ ll s = 0, w = 1; char ch = getchar(); while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); } while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar(); return s * w; } int Map[15]; int dp[15][1 << 15]; int main(){ int n,m; while(~scanf("%d%d",&n,&m)){ memset(dp,0,sizeof(dp)); memset(Map,0,sizeof(Map)); for(int i = 1 ; i <= n ; ++i){ for(int j = 0 ; j < m ;++j){ int x = read(); Map[i] = (Map[i] << 1) + x; } } dp[0][0] = 1; for(int i = 1 ; i <= n ; ++i){//第i行 for(int j = 0 ; j < (1 << m); ++j){//第i行的状态 if((j & (j >> 1)) || (Map[i] & j)!= j) continue; for(int k = 0 ; k < (1 << m) ; ++k){//枚举上一行 if(j & k) continue;//j有0的k都行,j有1的k必须为0 dp[i][j] = (dp[i][j] + dp[i-1][k])%mod; } } } ll ans = 0; for(int i = 0 ; i < (1 << m) ; ++i){ ans = (ans + dp[n][i]) % mod; } printf("%lld\n",ans); } }