sgu233 little kings

题目大意: 有n*n的棋盘上放k个国王。国王可以攻击与它相邻的八个格子。现在要使国王不相互攻击,有多少种放置的方案数。一个格子不能放两个国王。

n<=10,k<=n*n。

分析:简单的状态压缩DP。f[i][state][j]表示第i行放置国王的状态为state,前i行一共放了j个国王的方案数,state为位压缩表示的状态,某位为1,表示该处放了国王,为0表示没有放。合法的state状态数是有限的,所以,可以预处理出一行当中所有合法的state状态,保存在数组中。

f[i][p1][j]=∑(f[i-1][p2][j-cnts[state]]) {(state[p2]&state[p1])==0&&((state[p2]>>1)&state[p1]==0)&&((state[p2]<<1)&state[p1]==0)}

最后的答案即为∑f[n][j][k] {枚举j}

 1 #include<iostream>

 2 #include<cstdio>

 3 #include<cstring>

 4 using namespace std;

 5 int n,k,num=0,s[1200],c[1200];

 6 long long f[2][1100][120];

 7 void dfs(int i,int state,int cnt)

 8 {

 9     if(i>=n)

10     {s[++num]=state;

11      c[num]=cnt;

12         return;

13     }

14     dfs(i+1,state<<1,cnt);

15     if(state&1)return;

16     dfs(i+1,(state<<1)+1,cnt+1);

17 }

18 int main()

19 {

20     while(scanf("%d%d",&n,&k)!=-1)

21     {

22     memset(f,0,sizeof f);

23     num=0;

24     dfs(0,0,0);

25     for(int i=1;i<=n;i++)

26     {

27         for(int j=1;j<=num;j++)

28         {if(i==1)f[i&1][j][c[j]]=1;

29             else

30             for(int p=c[j];p<=k;p++)

31             {

32                 f[i&1][j][p]=0;

33                 for(int x=1;x<=num;x++)

34                 {

35                     if(c[x]+c[j]<=p&&(s[x]&s[j])==0&&((s[x]&(s[j]<<1))==0)&&((s[x]&(s[j]>>1))==0))

36                         f[i&1][j][p]+=f[!(i&1)][x][p-c[j]];

37                 }

38             }

39         }

40     }

41     long long ans=0;

42     for(int j=1;j<=num;j++)

43         ans+=f[n&1][j][k];

44     printf("%I64d\n",ans);

45 }

46 }

 

你可能感兴趣的:(it)