BZOJ 1087 互不侵犯的国王 状态压缩dp

来源:互联网 发布:ipad换壁纸软件 编辑:程序博客网 时间:2024/05/21 10:51

Description

  在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上
左下右上右下八个方向上附近的各一个格子,共8个格子。

Input

  只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)

Output

  方案数。

Sample Input

3 2

Sample Output

16

HINT


原题链接
首先这题其实可以不用dp。。可以打表。。
我还是要说说dp的做法吧。。(笑
状态压缩dp的基本东西我就不讲了。。
同所有状态压缩dp一样,既然题目要求每个单独行/每个相邻行整体的国王不产生冲突,
我们可以考虑简化问题,在dp的时候只考虑相邻两行的整体状态,所以一开始同样用一个dfs,
处理出所有同一行可以放的合法的状态。
比如n=3的时候,合法的状态有:
(在同一行之内)
十进制   二进制    国王个数
   0            0             0
   1           001          1
   2           010          1
   4           100          1
   5           101          2
(好像插入表格之后我就跳不到表格的下一行了
考虑动态规划:
Dp[u][Sta[e]][N]表示第u行,且第u行的状态是Sta[u],并且1~(u-1)行已经放下的国王个数共N个。
那么我们简单地得到方程:
(Num[e]表示第e种状态对应的一行内的国王个数)
Dp[u][Sta[e]][N+Num[e]]+=Dp[u-1][Sta[w]][N]
所以看到了,u,e,w,N都需要枚举。
什么时候可以转移呢?
条件一:Sta[e] and Sta[w]=0 ,这个比较好理解,不说了;
条件二:
  例如
101
010
也是不合法的相邻行。
所以我们可以判断一下Sta[e] or Sta[w]之后的值是否符合同一行内的满足条件(无相邻1)

初始化也简单:Dp[0][0][0]=1
那么答案呢?
只要将最后一行的所有合法状态Dp[n][Sta[e]][k]都累计起来就好了(k题目中给出)


还是比较入门的状压水题的。

#include<bits/stdc++.h>#define ll long longusing namespace std;const intStaNumMax=100,StaMax=1030; int n,kk,NumSta,g[10];int Sta[StaNumMax],Num[StaNumMax];ll f[15][StaMax][100];inline int read(){int x=0,f=1;char ch=getchar();while (ch<'0' || ch>'9'){if (ch=='-') f=-1;ch=getchar();}while (ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}inline void Count(int &x,int &y){int tmp1=0,tmp2=0;for (int i=1;i<=n;i++){tmp1+=(1<<(i-1))*g[i];if (g[i]) tmp2++;}x=tmp1; y=tmp2;}inline bool ok(int x){int tmp=-2;for (int i=0;i<=9;i++)if ((1<<i)&x){if (tmp==i-1) return false;tmp=i;}return true;}void dfs(int now){if (now>n){NumSta++;Count(Sta[NumSta],Num[NumSta]);return;}if (!g[now-1]){g[now]=1;dfs(now+1);g[now]=0;}dfs(now+1);}int main(){NumSta=0;n=read(),kk=read();dfs(1);memset(f,0,sizeof(f));f[0][0][0]=1;for (int i=1;i<=n;i++)for (int j=1;j<=NumSta;j++)for (int k=1;k<=NumSta;k++)for (int N=Num[k];N<=kk;N++)if (!(Sta[j]&Sta[k]) && ok(Sta[j]|Sta[k]))f[i][Sta[j]][N+Num[j]]+=f[i-1][Sta[k]][N];ll ans=0;for (int i=1;i<=NumSta;i++)ans+=f[n][Sta[i]][kk];printf("%lld\n",ans);return 0;} 


原创粉丝点击