您的位置:首页 > 其它

【bzoj1087】互不侵犯King 状态压缩dp

2016-11-15 21:49 309 查看
AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1087

【题解】

用f[i][j][k]表示前i行放了j个棋子且第i行的状态为k的方案数。

vis[i]表示状态i是否合法,check[i][j]表示状态i,j是否可以相邻。

详见代码:

/*************
bzoj 1087
by chty
2016.11.15
*************/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
#define FILE "read"
#define up(i,j,n) for(ll i=j;i<=n;i++)
namespace INIT{
char buf[1<<15],*fs,*ft;
inline char getc() {return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
inline ll read() {
ll x=0,f=1;  char ch=getc();
while(!isdigit(ch))  {if(ch=='-')  f=-1;  ch=getc();}
while(isdigit(ch))  {x=x*10+ch-'0';  ch=getc();}
return x*f;
}
}using namespace INIT;
ll n,m,ans,vis[1<<9],sum[1<<9],check[1<<9][1<<9],f[11][121][1<<9];
void pre(){
up(i,0,(1<<n)-1)if(!(i&(i<<1))){vis[i]=1; for(ll x=i;x;x>>=1)  sum[i]+=(x&1);}
up(i,0,(1<<n)-1){
if(!vis[i])  continue;
up(j,0,(1<<n)-1){
if(!vis[j]||(i&j)||(i&(j>>1))||(j&(i>>1)))  continue;
check[i][j]=1;
}
}
}
int main(){
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
n=read();  m=read();
pre();  up(i,0,(1<<n)-1) if(vis[i]) f[1][sum[i]][i]=1;
up(i,2,n)up(j,0,(1<<n)-1){
if(!vis[j])  continue;
up(k,0,(1<<n)-1){
if(!vis[k]||!check[j][k])  continue;
up(p,sum[k],m-sum[j])  f[i][p+sum[j]][j]+=f[i-1][p][k];
}
}
up(i,0,(1<<n)-1)  ans+=f
[m][i];
printf("%lld\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: