圧力シリーズIIのように。
タイトル効果:与えられた\(N * m個\)位置のいくつかを置くことができるマトリックス、一部はできません。グリッドの規定は、左を入れて、右のそれを置くことはできません。どのように多くのグリッドプログラムを置くことを求めました。
考慮\(N、Mの\)は圧力の形状であるように、小さいです。
圧力のような表現を考えてみましょう、私たちは各ラインに置く\(01 \)バイナリに押し込ま行列を、それはラインのステータスを示します。
だから我々は明らかに、圧力ラインを終えた後、\(N \)数は、各ラインのステータスを示します。すなわち、状態の総数である\(N-2 ^ \) 。
また、ので、それは右に置くと、それを処理するために、その後、最初のそのような法的地位をままにすることはできません。
考慮されていき\(DP \) 。
各行(圧縮された状態)を介して、各状態のために、ステータスに対応することができるものを列挙し、その次の行の状態が対応することができます。私たちは、正規のプログラムブール配列であなたの経験の前に置くことができます。
だから我々は最初の合法的な状態を選択する必要があります。第二に、この状態は、タイトルに植えられた地域の地図を与えることはできません。我々は使用することができます\(J&MP [i]を == jは\)を法的かどうかを判断します。
それでは次の行の状態を列挙。明らかに、最大2行下に隣接することはできません\(1 \)を、\ (J&K \)ができます。
そして、それは、累積状態に愛されています。
トピックが行わ。左右の判決なお、これらのことができます。
$ I&(I << 1)== 0 $ \(&& \) \(I&(I >> 1)== 0 \)
優先順位、習慣の括弧に注意してください。
\(コード:\)
#include<iostream>
using namespace std;
int n,m,a[20][20],mp[20];
int dp[20][5000],Ans;
bool state[5000];
const int Hws=100000000;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
scanf("%d",&a[i][j]);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
mp[i]=(mp[i]<<1)+a[i][j];
for(int i=0;i<(1<<m);++i)if(((i&(i<<1))==0)&&((i&(i>>1)))==0)state[i]=1;
dp[0][0]=1;
for(int i=1;i<=n;++i){
for(int j=0;j<(1<<m);++j)
if(state[j]&&((j&mp[i])==j)){
for(int k=0;k<(1<<m);++k)
if((k&j)==0){
dp[i][j]+=dp[i-1][k];
dp[i][j]%=Hws;
}
}
}
for(int i=0;i<(1<<m);++i)Ans+=dp[n][i],Ans%=Hws;
printf("%d\n",Ans);
return 0;
}