题意:Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. some of the squares are infertile and can't be planted. (1 for fertile, 0 for infertile)cows dislike eating close to each other。Please help Farmer John determine the number of ways he can choose the squares to plant.
第一道状态压缩DP题,写的还挺顺利的。
第一具备位运算常识:
“&” 按位与: 3: 0011, 5:0101; 那么3&5: 0011
& 0101
0001
那么意味着只要有一位上都是1,那么&的结果就是>0 d的。
“|” 按位或 只要俩个数字有一位是1 ,那么|的结果中相应位为1 3|5=0111;
“<<" :
x<<y 意思是x左移多少多少位 : 1<<4 是00001<<4 等于 01000
3<<5 是 00011 <<3 等于 11000
第二:
状态压缩DP,在我的理解中就是应用二进制数去标记所有状态。在根据二进制数本身特点去识别是不是有效状态。
根据代码解释:dp[i][j]表示第i 行状态j 的方案数
dp[i][j]=dp[i][j]+dp[i-1][j] (j为所有合法状态)
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int MOD=100000000;
int dp[13][1<<12]={0,0,0};
int n,m;
int OK[1<<13];
int map[1<<13];
int main()
{
// freopen("in.txt","r",stdin);
memset(dp,0,sizeof(dp));
scanf("%d%d",&n,&m);
int cnt=0;
memset(OK,0,sizeof(OK));
for(int i=0; i< (1<<m);i++) // 枚举所有合法状态: i是一个没有连续位为1的数,如i=5:0101
if(!(i&(i<<1))) OK[cnt++]=i; //cnt为所有合法状态的总数
int t;
memset(map,0,sizeof(map));
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
scanf("%d",&t);
if(t==0) map[i]=map[i]|(1<<j); //用map去记录每行不可以使用的土地的状态。
} //例如某一行 1 0 0 0 那么这行map[x]就为0111;
for(int i=0;i<cnt;i++)
if(!(map[0]&OK[i])) dp[0][i]=1;
//处理第一行
for(int r=1;r<n;r++) for(int i=0;i<cnt;i++)
{
if(map[r]&OK[i]) continue;
for(int j=0;j<cnt;j++)
{
if(map[r-1]&OK[j]||OK[i]&OK[j]) continue;
dp[r][i]=(dp[r][i]+dp[r-1][j])%MOD;
}
}
int ans=0;
for(int i=0;i<cnt;i++)
ans=(ans+dp[n-1][i])%MOD;
printf("%d\n",ans);
return 0;
}