題目大意: 一個農民有一片n行m列 的農場 n和m 范圍[1,12] 對於每一塊土地 ,1代表可以種地,0代表不能種。 因為農夫要種草喂牛,牛吃草不能挨著,所以農夫種菜的每一塊都不能有公共邊。 告訴你 n ,m 和那些地方能種菜哪些地方不能種菜,求農夫一共有多少種方案種菜
解法:
基本思想是狀壓 也就是用一個int 型的數代表一行的種菜策略,二進制的0代表該位不能種菜,1位代表能種菜,使用位運算使處理速度變快
對於單行行,最多有2^12 種情況,並且 2^12種情況裡面還有很多不滿足題意的 篩選一下每行最多有400左右種情況,
1 先篩選出每行滿足題意的情況
2 如何判斷兩行能否相鄰? 如果一行狀壓的數使 i 另一行狀壓的數是 j 如果 i|j ==i+j 說明兩行可以相鄰
3 如何判斷一個種法能否滿足某一行的要求?
以樣例來看
2 3
1 1 1
0 1 0
第一行二進制是7 第二行二進制是2
如果一個種菜的決策時 i 如果 i|2==2 就說明他能滿足第二行的要求,,
然後就是dp[i][k] 代表第i行像k這樣種菜的情況數
然後就是渣渣參考代碼 g++
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <string>
#include <queue>
#include <cstring>
#define CL(a,b) memset(a,b,sizeof(a))
#define ll __int64
#define TEST cout<<"TEST ***"<<endl;
#define INF 0x7fffffff
#define MOD 100000000
using namespace std;
ll dp[15][1000];
int inn[4100],m,n;
int num[12];
int initinn()
{
int i,j,preinn,nowinn,taginn;
CL(inn,0);
for(i=0;i<4100;i++)
{
preinn=0,taginn=1;
j=i;
while(j)
{
nowinn=j&1;
if(nowinn==1&&preinn==1)
{
taginn=0;
break;
}
preinn=nowinn;
j/=2;
}
inn[i]=taginn;
}
i=0;j=0;
while(j<4100)
{
if(inn[j]==1)
{
inn[i++]=j;
}
j++;
}
return i;
}
using namespace std;
int main()
{
initinn();
while(scanf("%d %d",&n,&m)!=EOF)
{
int i,j,k,ma=(1<<m)-1;
int a,sum;
CL(dp,0);
for(i=1;i<=n;i++)
{
sum=0;
for(j=0;j<m;j++)
{
scanf("%d",&a);
sum*=2;
sum+=a;
}
num[i]=sum;
}
dp[0][0]=1;
for(i=1;i<=n;i++)
{
for(j=0;inn[j]<=ma;j++)
{
if((inn[j]|num[i])!=num[i])continue;
for(k=0;inn[k]<=ma;k++)
{
if((inn[j]|inn[k])==inn[j]+inn[k])
{
dp[i][j]+=dp[i-1][k];
dp[i][j]%=MOD;
}
}
}
}
ll rem=0;
for(i=0;inn[i]<=ma;i++)
{
rem+=dp[n][i];
}
rem%=MOD;
printf("%I64d\n",rem);
}
return 0;
}