现在的位置: 首页 > 综合 > 正文

BZOJ1087

2018年05月02日 ⁄ 综合 ⁄ 共 968字 ⁄ 字号 评论关闭

    这是一道状压DP题,不必想的太复杂。

     关键就在于如何进行上下的转换;

    f[ i ][ j ][ t ] 表示第i行,j 表示 有几个国王,t 表示在 第 i 行的分布状态;

    t 的状态可以先预处理;注意上一层国王影响的将会是下一层的三个结点;


  

#include<cstdio>
#include<cstdlib>
#include<cstring>
long long a[1024],b[1024];
long long f[10][82][1023];
bool w[1023][1023];
bool ok(int x,int &d){
	int p=0;int tot=0;
	while(x>0){
		if ((x&(-x))<=p*2)return false;
		 else {p=x&(-x);x-=p;tot++;}
	}
	d=tot;return true;
}
int main()
{
	//freopen("king.in","r",stdin);
	//freopen("king.out","w",stdout);
	int n,k;scanf("%d%d",&n,&k);
	int q=(1<<n)-1,l=0,d;
	memset(w,false,sizeof(w));
	for(int i=0;i<=q;i++)
	 if(ok(i,d)==true){
		l++;a[l]=i;b[l]=d;
		for(int y=1;y<=l;y++)
		 if(((a[y]&i)==0)&&(((a[y]>>1)&i)==0)&&(((i>>1)&a[y])==0))w[l][y]=w[y][l]=true;
	 }
	memset(f,0,sizeof(f));
	for(int j=1;j<=l;j++)
	 if(b[j]<=k)f[1][b[j]][a[j]]=1;
	for(int i=2;i<=n;i++)
	  for(int j=1;j<=l;j++)
	   for(int t=1;t<=l;t++)
	   if(w[j][t]==true)
	     for(int p=b[j];p+b[t]<=k;p++)
	      f[i][p+b[t]][a[t]]+=f[i-1][p][a[j]];
	long long ans=0;
	for(int i=1;i<=l;i++)ans+=f[n][k][a[i]];
	printf("%I64d\n",ans);
	//system("pause");
	return 0;
}

抱歉!评论已关闭.