最近被状态压缩DP虐得不行,今天终于决定正视自己的弱项,好好把DP练习一下,把今天做的几道状态压缩DP总结一下,一定要想办法摆脱DP弱菜这个标签!!!
http://poj.org/problem?id=3254
poj 3254 :
应该是最基础的状态压缩DP了吧,设dp[i][flag]表示第i行状态为flag时的排放总数,预处理一下dp[1][flag],对于dp[i][flag](i>=2),则dp[i][flag]=dp[i][flag]+dp[i-1][pre]当且仅当pre满足以下几个条件:
1:flag和pre都不含有相邻的1(二进制)
2:flag和pre分别满足第i行和第i-1行的约束条件。
3:flag和pre在同一位上不能同时为1(二进制)。
还是挺简单的,用位运算可以简单实现。代码如下:
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <vector>
#define mod 100000000
using namespace std;
vector<int> t;
int check(int x)
{
int i;
for(i=0;i<=10;i++)
{
int tmp=(1<<i)+(1<<(i+1));
if((x&tmp)==tmp)
return 0;
}
return 1;
}
void init()
{
int i;
t.push_back(0);
for(i=1;i<(1<<12);i++)
{
if(check(i))
t.push_back(i);
}
}
int dp[13][400];
int num[13];
int main()
{
//freopen("dd.txt","r",stdin);
init();
int n,m,i,j;
scanf("%d%d",&n,&m);
memset(dp,0,sizeof(dp));
for(i=1;i<=n;i++)
{
int tmp=0;
for(j=1;j<=m;j++)
{
int x;
scanf("%d",&x);
tmp=tmp*2+x;
}
num[i]=tmp;
}
int limit=1<<m,len=t.size();
long long ans=0;
for(i=0;i<len;i++)
{
if(t[i]>=limit)
break;
int now=t[i];
if((now|num[1])==num[1])
{
dp[1][i]=1;
}
}
for(i=2;i<=n;i++)
{
for(j=0;j<len;j++)
{
if(t[j]>=limit)
break;
int now=t[j],s;
if((now|num[i])==num[i])
{
for(s=0;s<len;s++)
{
if(t[s]>=limit)
break;
int pre=t[s];
if((num[i-1]|pre)==num[i-1]&&(pre&now)==0)
{
dp[i][j]=(dp[i][j]+dp[i-1][s])%mod;
}
}
}
}
}
for(i=0;i<len;i++)
{
if(t[i]>=limit)
break;
ans=(ans+dp[n][i])%mod;
}
printf("%I64d\n",ans);
retur