poj 3254 状态压缩DP

时间:2022-10-13 08:13:02

思路:把每行的数当做是一个二进制串,0不变,1变或不变,找出所有的合法二进制形式表示的整数,即相邻不同为1,那么第i-1行与第i行的状态转移方程为dp[i][j]+=dp[i-1][k];

这个方程得前提条件是num[i][j]&num[i-1][k]==0,也就是他们表示的二进制形式相与为0,那么就不存在相邻为1的情况。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define Maxn 13
#define inf 0x7fffffff
using namespace std;
__int64 dp[Maxn][<<Maxn];
int num[][<<Maxn],cnt1,cnt2,graphic[Maxn][Maxn],co,n,m;
void dfs(int u,int j)
{
int i;
if(j==m)
{
int sum=;
for(i=m;i>=;i--)
sum+=graphic[u][i]*(<<(m-i));
if(graphic[u][j]==)
{
if(graphic[u][j-]==)
{ num[u][++cnt2]=sum;
num[u][++cnt2]=sum-;
}
else
{
num[u][++cnt2]=sum-;
}
}
else
num[u][++cnt2]=sum;
return ;
}
if(graphic[u][j]==)
{
if(graphic[u][j-]==)
{
dfs(u,j+);
graphic[u][j]=;
dfs(u,j+);
graphic[u][j]=;
}
else
{
graphic[u][j]=;
dfs(u,j+);
graphic[u][j]=;
}
}
else
dfs(u,j+);
}
int main()
{
int i,j,k;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(dp,,sizeof(dp));
for(i=;i<=n;i++)
for(j=;j<=m;j++)
scanf("%d",&graphic[i][j]);
for(i=;i<=n;i++)
graphic[i][]=;
cnt2=;
dfs(,);
for(i=;i<=cnt2;i++)
dp[][i]=;
for(i=;i<=n;i++)
{
cnt1=cnt2;cnt2=;
dfs(i,);
for(j=;j<=cnt2;j++)
{
for(k=;k<=cnt1;k++)
{
if(!(num[i-][k]&num[i][j]))
dp[i][j]+=dp[i-][k],dp[i][j]%=;
}
}
}
__int64 ans=;
for(i=;i<=cnt2;i++)
ans+=dp[n][i];
printf("%I64d\n",ans%);
}
return ;
}