状态压缩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行一个都不摆地状态中了
	}
  

最后:三年OI一场空,不开longlong(范围开反)见祖宗

posted @ 2022-01-25 09:14  artalter  阅读(33)  评论(0编辑  收藏  举报