题意:
有n*m的方格上,输入时1表示土地肥沃,0表示贫瘠,牛只能在肥沃的土地上生存,且两头牛不能相邻(上下左右),问有几种放牛的方法
由题目N,M的范围便可联想到用状态压缩
思路:
输入时处理出每一行上的土地的二进制的和,保存在mp[i]数组中,i表示第几行
比如 1 0 0 1—-mp[1]遍等于6,2^1+2^2=6;
接下来的每一行都是如此
先预处理出每一行上有几种不同的放牛方式,–称之为状态数,每一行可以放几种不同的状态,程序中表示为state数组
根据dp的原则便可知道,从局部推向整体,
所以下一行一定是有上一行推出的,且上下两行之间没有相邻的,这里有一个特殊的技巧,只要上一行的放置二进制转化成的十进制与下一行的放置二进制转化成的十进制相&,如果不为1,则表示上下无相邻
则dp[i][j]+=dp[i-1][f]; i表示第几列,j,f表示状态数
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define inf -0x3f3f3f3f
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define mem(a, b) memset(a, b, sizeof(a))
typedef long long ll;
const int MOD=100000000;
int mp[14];
int state[10000];
ll dp[13][10000];
bool judge1(int x){
return x&(x>>1);
}
bool judge2(int i,int x){
return mp[i]&state[x];
}
int main(){
int n,m,x;
while(scanf("%d%d",&n,&m)!=EOF){
mem0(mp);
mem0(dp);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
scanf("%d",&x);
if(x==0){
mp[i]+=1<<(j-1);
}
}
int k=0;
for(int i=0;i<(1<<m);i++){
if(!judge1(i)){
state[k++]=i;
}
}
for(int i=0;i<k;i++){
if(!judge2(1,i)){
dp[1][i]=1;
}
}
for(int i=2;i<=n;i++)
for(int j=0;j<k;j++){
if(judge2(i,j))
continue;
for(int h=0;h<k;h++){
if(judge2(i-1,h))
continue;
if((state[j]&state[h])==0)
dp[i][j]=(dp[i][j]+dp[i-1][h])%MOD;
}
}
int ans=0;
for(int i=0;i<k;i++){
ans=(ans+dp[n][i])%MOD;
}
printf("%d\n",ans);
}
return 0;
}
其他思考:
1.如果牛的数目固定
2.方向改为上下左右,左上左下右上右下
3.每一头牛不能再同一行同列