状态压缩DP总结
状态压缩DP总结(然而现在一共只打了两道题,边打边写)
P1896 互不侵犯 不可能
f[i][j][k]表示在第i行以j的摆放方式在前i行共摆放k个棋子的方案叔
一个国王拜访的位置受到左,下,左下,右下四个方位的影响
因此,如果这一行棋子摆放的方式为s1,上一行棋子摆放的方式为s2,那么s1&s2=0,s1&(s2<<1)=0,s1&(s2>>1)=0(解决了下,左下,右下
并且,我们可以预处理出每一行可能出现的状态sit(set)+这个状态中1的数量(也就是这一行摆放的国王的数量)gs(解决了右
现在,状态转移方程可以表示为f[i][s1][s]=sum(f[i-1])[s1][s-gs[s1]]
初始状态:第一行所有状态的方案数都是1
下面贴代码:
预处理
void dfs(long long num,long long sum,long long node)
{
if(node>=n)
{
cnt++;
sit[cnt]=num;
gs[cnt]=sum;
return;
}
dfs(num+(1<<(node)),sum+1,node+2);
dfs(num,sum,node+1);//我们求的状态中包括一行中什么都不摆的
}
赋初值
for(long long i=1;i<=cnt;i++)
{
f[1][i][gs[i]]=1;
}
核心代码
for(long long i=2;i<=n;i++) { for(long long j=1;j<=cnt;j++) { for(long long s=1;s<=cnt;s++) { if(sit[j]&sit[s])continue; if(sit[j]&(sit[s]>>1))continue; if(sit[j]&(sit[s]<<1))continue;
for(long long u=k;u>=gs[j];u--)f[i][j][u]+=f[i-1][s][u-gs[j]]; } } }
结尾求值
long long ans=0;
for(int j=1;j<=cnt;j++)
{
ans+=f[n][j][k];//在前n-1行放完k个棋子的状态被包括在第n行一个都不摆地状态中了
}