[SCOI2005]互不侵犯————状压DP

题解:本题主要考查状压DP
简要题意:在 N × N N×N N×N的棋盘里面放 K K K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向。
1.状压DP:看到数据范围 1 < = N < = 9 1<=N<=9 1<=N<=9,就应该想到算法应是状压DP或搜索,明显这题用状压DP更好。状态压缩其实是一种并没有改变dp本质的优化方法。
d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]表示第 i i i行,状态为 j j j,前面摆了 k k k个国王时的方案数。
方程不难: d p [ i ] [ j ] [ k i n g [ j ] + p ] + = d p [ i − 1 ] [ k ] [ p ] dp[i][j][king[j]+p]+=dp[i-1][k][p] dp[i][j][king[j]+p]+=dp[i1][k][p]; k i n g [ i ] king[i] king[i]表示第 i i i行的国王数。
但是要求国王互不攻击,所以要预处理行的情况,并且优化时间复杂度。再处理行与行之间的关系。
总结:
代码如下:

#include
#include
#include
#include
using namespace std;
int state[26666],king[26666];
long long dp[11][2000][160];//hang,zht,suoyong
long long n,K,ans,sum;
void pre()
{
	for(int i=0;i<=(1<>=1;}
		}
	}
}
int main()
{
	cin>>n>>K;
	pre();
	for(int i=1;i<=sum;i++)
	if(king[i]<=K)dp[1][i][king[i]]=1;
	
	for(int i=2;i<=n;i++)
	for(int j=1;j<=sum;j++)
	for(int k=1;k<=sum;k++)
	{
		if(state[j]&state[k])continue;
		if((state[j]<<1) & state[k])continue;
		if(state[j] & (state[k]<<1))continue;
		for(int p=1;p<=K;p++)
		{
			if(king[j]+p>K)continue;
			dp[i][j][king[j]+p]+=dp[i-1][k][p];
		}
	}
	for(int i=1;i<=n;i++)
	for(int j=1;j<=sum;j++)
	ans+=dp[i][j][K];
	cout<

你可能感兴趣的:(DP)