我的第一道状态压缩DP,神奇的二进制。
对着别人的代码思索了思索了许久才弄明白。然后自己写了一遍,忘了对M求余,wa了一次。
最起码在这道题中,实际上通过状态压缩并没有减少运算量,但是通过二进制来比较不同列的两种状态的效率非常高。实际上思路还是挺暴力的。。。。
#include<stdio.h>
#include<string.h>
#define N 13
#define M 100000000
int s[N],f[N][1<<N];
int m,n;
void input()
{
scanf("%d%d",&m,&n);
int i,j;
for(i=1;i<=m;i++)
{
s[i]=0;
for(j=0;j<n;j++)
{
int temp;
scanf("%d",&temp);
s[i]=(s[i]<<1)+temp;
}
}
return ;
}
int judge(int a,int b)
{
if((a&s[b])!=a)//如果a&s[b]!=a,说明在第b列中根本没有a这种状态,不用考虑。
return 1;
int x=3;//这个地方非常巧妙,3的二进制表示是11,通过在1后面逐个补0和a比较,来判断a中有没有连续的两个1。
int i;
for(i=1;i<n;i++)
{
if((a&x)==x)
return 1;
x<<=1;
}
return 0;
}
void output()
{
int i,j,k;
int tt=1<<n;
memset(f,0,sizeof(f));
f[0][0]=1;
for(i=1;i<=m;i++)
{
for(j=0;j<tt;j++)
{
if(judge(j,i))
continue;
for(k=0;k<tt;k++)
{
if((j&k)==0)//如果j&k==0,说明j和k这两个状态完全没有矛盾的地方。
f[i][j]=(f[i][j]+f[i-1][k])%M;
}
}
}
int sum=0;
for(i=0;i<tt;i++)
sum=(sum+f[m][i])%M;;
printf("%d\n",sum);
return ;
}
int main()
{
input();
output();
return 0;
}