农夫约翰的土地由 M×N= 个小方格组成,现在他要在土地里种植玉米。
非常遗憾,部分土地是不育的,无法种植。
而且,相邻的土地不能同时种植玉米,也就是说种植玉米的所有方格之间都不会有公共边缘。
现在给定土地的大小,请你求出共有多少种种植方法。
土地上什么都不种也算一种方法。
输入
第 1 行包含两个整数 M 和 N (1 ≤ M,N ≤ 12)。
第 2..M+1 行:每行包含 N 个整数 0 或 1,用来描述整个土地的状况,1 表示该块土地肥沃,0 表示该块土地不育。
输出
输出总种植方法对 1e8 取模后的值。
Input
2 3
1 1 1
0 1 0
Output
9
解析:
板子题,不过对于每一行有不能种植的地方,在枚举合法状态的时候,需要特判一下,将不能种植的地方种植的状态要跳过,这样的状态是不合法的。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define ios ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int gcd(int a,int b) { return b? gcd(b,a%b) : a; }
typedef pair<int,int> PII;
const double PI=acos(-1.0);
const int N=14,M=1<<12,mod=1e8;
int n,m;
int g[N];
vector <int> state;
vector <int> head[M];
int f[N][M];
bool check (int x) //一行中相邻两项不能同时为1,也就是不能同时种植
{for (int i=0;i<m;i++){if ((x>>i&1)&&(x>>i+1&1)) return 0;}return 1;
}
void solve()
{cin>>n>>m;for (int i=1;i<=n;i++)for (int j=0;j<m;j++){int x;cin>>x;g[i] += !x*(1<<j); //1代表该位置不能被种植,0代表该位置能被种植}for (int i=0;i<1<<m;i++) //预处理一行中所有合法的状态,一行的相邻两项不能同时为1,就是合法状态{if (check(i)) state.push_back(i);}for (int i=0;i<state.size();i++) //预处理两行中所有合法的状态,两行的同一列不能同时为1,就是合法状态for (int j=0;j<state.size();j++){int a=state[i],b=state[j];if ((a&b)==0) head[a].push_back(b);}f[0][0]=1;for (int i=1;i<=n+1;i++)for (auto a:state)for (auto b:head[a]){if (g[i]&a) continue; //此处,&运算,同1则1,说明此时合法状态 a 和g[i]不能种植的位置 都存在1,与题意不符,跳过f[i][a]=(f[i][a]+f[i-1][b])%mod;}cout<<f[n+1][0]<<endl;
}
signed main()
{ios;int T=1;//cin>>T;while (T--) solve();return 0;
}