现在对简单题的态度也变了,觉得简单题未必不能帮助你提高。简单题往往更裸,更能单独体现某一个知识点或者技巧。而复杂题目往往是几种技巧的组合使用。
这是一道入门的状态压缩DP。
在一个棋盘上选择一些不相邻的点(上下左右),求这些点的总数。有一些点不可选。
首先把每行可能的状态保存下来。存在state里面,因为限制了不相邻,所以这样一轮筛选之后单行的状态数就已经少了很多。
然后对每一行i 枚举所有可能到达这个状态的 i-1行的状态。因为状态只和上一行有关。然后求和就可以了。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int dp[20][500];
const int MOD=100000000;
int tot;
int state[500];
void init(int n)
{
int k=1<<n;
for(int i=0;i<k;i++)
{
if((i&(i<<1))==0)
state[tot++]=i;
}
}
int row[100];
int main()
{
int m,n;
scanf("%d%d",&m,&n);
memset(row,0,sizeof(row));
memset(dp,0,sizeof(dp));
memset(state,0,sizeof(state));
init(n);
for(int i=0;i<m;i++)
{
for(int j=n-1;j>=0;j--)
{
int k;
scanf("%d",&k);
row[i]+=(k<<j);
}
}
for(int i=0;i<tot;i++)
{
if( ( row[0] & state[i] ) == state[i] )
dp[0][i]=1;//代表第i个状态 不表示状态是i
}
for(int i=1;i<m;i++)
{
for(int j=0;j<tot;j++)//本行状态
{
if((row[i]&state[j])==state[j])//可满足
{
for(int k=0;k<tot;k++)//前一行状态
{
if(dp[i-1][k]&&(((state[k])&state[j])==0))
{
dp[i][j]=(dp[i-1][k]+dp[i][j])%MOD;
}
}
}
}
}
int sum=0;
for(int i=0;i<tot;i++)
{
sum=(sum+dp[m-1][i])%MOD;
}
printf("%d\n",sum);
return 0;
}