编程兔暑假3.5阶段集训Day6——状压(状态压缩)dp、dp优化以及图论

编程兔暑假3.5阶段集训Day6——状压(状态压缩)dp、dp优化以及图论

        今天我们先来讲一下状态压缩dp(也称状压dp)。状压dp,顾名思义,就是把状态压缩起来。比如对于8*8 的棋盘,每个位置可以放一个棋子,对于在第i行第2个位置和第6个位置放了棋子,我们可能需要8维或9维数组表示。因此我们就有了把一行状态压缩成一个数字的做法。一般我们会转化为二进制,如果每个位置可以有3种状态,那我们可以采用三进制。这样只需要一个大小为2^8的一维数组我们就可以存下所有状态,这就是状态压缩。

eg1
• 现在有 n*m 的方格棋盘,和无限的 1*2 的骨牌,问有多少种方法能用骨牌 铺满棋盘。
• 1<=n,m<=11.

算法分析:
首先 n*m 是奇数一定拼不出来。使用状态压缩,如果第 i 个位置上放骨牌,就在二进制对应位置填 1,否则是 0. 用 f[i][s] 表示填到了第 i 行状态是 s 的方案数。答案就是 f[n][(1<<m)-1]。可是怎样进行状态的转移呢?
首先我们的决策有两种:横着放或者竖着放。
我们需要连续考虑二行,如果横着放,需要两个连续的空位,且上一行这两个位置也被覆盖;如果竖着放有2种情况:
    1、上一行位置是空的,我们就可以把空填上。
    2、上一行是覆盖的,那么我们把这一行位置设为空,表示下一行必须竖着放 填上这块空白。

代码实现:
void dfs(int i,int now,int pre)
{
	if(i>m)
	{
		return ;
	}
	if(i==m)
	{
		++tot;
		from[tot]=pre;
		to[tot]=now;
		return ;
	}
	dfs(i+2,now<<2|3,pre<<2|3);
	dfs(i+1,now<<1,(pre<<1)|1);
	dfs(i+1,now<<1|1,pre<<1);
}

主函数: 
int f[12][1<<11];
dfs(0,0,0);
f[0][(1<<m)-1]=1;
for(int i=0;i<n;i++)
{
	for(int j=1;j<=tot;j++)
	{
		f[i+1][to[j]]+=f[i][from[j]];
	}
}
hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » 编程兔暑假3.5阶段集训Day6——状压(状态压缩)dp、dp优化以及图论