您的位置:首页 > 其它

POJ 2411 状态压缩DP

2014-01-11 11:41 323 查看
第一次做状态压缩DP,是因为按照DP清单里面碰到了状态不确定的DP,我当时只能用回溯做,但是时间卡得想死啊,后来又连续碰到几个题目都需要用状态压缩,所以好好学了一下,说到这里,必须要检讨一下昨天的自己,其实这道题目本应该昨天完成的,自己磨磨蹭蹭昨天非常地心不在焉,弄得昨天完全没完成训练任务。加上这个位运算这里确实有点难懂,我之前很少接触位运算,但是用状态压缩的时候位运算贯穿整个代码,所以理解起来比较难

还好找到了一个讲解非常详细的博文,这才理解了 http://www.2cto.com/kf/201208/146894.html 这个博文写的非常好

还有这个题目跑了900+MS,在学校的VJ上有100+MS过的,我看了下,先用的一个dfs在预处理,我没怎么看懂为什么是么是这样搞。。。。再说吧

注意两点:1。结果可能非常大,因此要用long long

2.行如果小于列的话,交换一下,能大大缩小时间复杂度,因为m的递增导致循环里面是成指数的增长

继续加油

#include <iostream>
#include <cstdio>
#include <cstring>
#define N (1<<11)+20
#define ll long long
using namespace std;
ll dp[12]
;
int n,m;
bool testfirst(int d)
{
int i=0;
while (i<m)
{
if (d & (1<<i))
{
if (i==m-1 || (d & (1<<(i+1)))==0)
{
return false;
}
i+=2;
}
else
i++;
}
return true;
}
bool test(int a,int b)
{
int i=0;
while (i<m)
{
if ((a & (1<<i))==0)
{
if ((b & (1<<i))==0)
return false;
i++;
}
else
{
if ((b & (1<<i))==0)
i++;
else
{
if (i==m-1 || !(a& (1<<(i+1))) || !(b & (1<<(i+1))))
{
return false;
}
i+=2;
}
}
}
return true;
}
int main()
{
int i,j,k;
while (scanf("%d%d",&n,&m))
{
if (n+m==0) break;
if (n*m%2!=0)
{
puts("0");
continue;
}
if (n<m)
{
int temp=n;
n=m;
m=temp;
}
memset(dp,0,sizeof dp);
for (i=0; i<N; i++)
{
if (testfirst(i))
{
dp[0][i]=1;
}
}
for (i=1; i<n; i++)
{
for (j=0; j<(1<<m); j++)
{
for (k=0; k<(1<<m); k++)
{
if (test(j,k))
{
dp[i][j]+=dp[i-1][k];
}
}
}
}
printf("%lld\n",dp[n-1][(1<<m)-1]);
}
return 0;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: