sgu223 Little Kings 状压DP

   N*N的棋盘,放k个兵,兵可以攻击相邻八面.问在任意两兵不互相攻击的情况下,有多少种放置方法。跟第一页的那两个状压DP差不多,好像还要简单点,因为只有10*10,滚动数组也不用开了...dp[i][j][k]表示对i行放置,若第i行的状态是j,此时共放置了k个兵。对每一行dfs枚举放置的方案,每次dfs的时候记录一下当前行状态,某个位置放置后对下一行的状态影响,放置位置,当前行放了几个兵。具体实现看代码吧。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
int n,m,p,k,q;
int tgt;
int ans;
int nn;
ll f[13][2099][110];
int tmpi,tmpj,tmpk;
bool ocp(int sta,int pos)
{
    return (sta & (1<<pos));
}
void dfs(int now,int sta,int ns,int num,int pos,ll cnt)
{
   if (pos==n)
   {
       f[now+1][ns][tmpk+cnt]+=f[now][tmpj][tmpk];
       return;
   }
   dfs(now,sta,ns,num,pos+1,cnt);
   if (!ocp(sta,pos))
   {
       int tpa=sta,tpb=ns;
       tpa|=(1<<pos);
       if (pos>0) tpa|=(1<<(pos-1));
       if (pos<n-1) tpa|=(1<<(pos+1));

       tpb|=(1<<pos);
       if (pos>0) tpb|=(1<<(pos-1));
       if (pos<n-1) tpb|=(1<<(pos+1));
       dfs(now,tpa,tpb,num,pos+1,cnt+1);
   }
}
int main()
{
    scanf("%d%d",&n,&tgt);
    memset(f,0,sizeof f);
    f[1][0][0]=1;
    int nn=1<<n;
    for (int i=1; i<=n+1; i++)
     for (int j=0; j<nn; j++)
      for (int k=0; k<tgt; k++)
      if (f[i][j][k])
      {
          tmpj=j;
          tmpk=k;
          dfs(i,j,0,k,0,0);
      }
     for (int i=1; i<=n+1; i++)
      for (int j=0; j<nn; j++)
       ans+=f[i][j][tgt];
       cout<<ans<<endl;
    return 0;
}

你可能感兴趣的:(sgu223 Little Kings 状压DP)