<SCOI2005>互不侵犯の思路
日常玄学dp
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 int n,k,judge[1000],num[1000]; 7 long long dp[10][100][1000];//注意开ll..一开始就死在数组开小和没开ll 8 void init() 9 { 10 int i,t; 11 for(i=0;i<(1<<n);i++) 12 { 13 if(!(i&(i<<1)))//i这行没有1粘一块儿 14 { 15 judge[i]=1; 16 t=i; 17 while(t) 18 { 19 num[i]+=(t&1);//有几个王 20 t>>=1;//移回一位 21 } 22 } 23 dp[1][num[i]][i]=1; 24 } 25 } 26 int main() 27 { 28 int i,j,now,last; 29 long long ans=0; 30 scanf("%d%d",&n,&k); 31 init();//初始化第一行的各种状态 32 for(i=2;i<=n;i++)//枚举n行 33 for(j=0;j<=k;j++)//枚举有0~k个王 34 for(now=0;now<(1<<n);now++)//枚举现在的状态 35 { 36 if (!judge[now])//如果有王粘一块儿 37 continue; 38 if (num[now]>j)//这个状态有比j多的王 39 continue; 40 for(last=0;last<(1<<n);last++)//枚举上一个 41 { 42 if(!judge[last]) continue; 43 if((last&now) || ((now<<1)&last) || ((now>>1)&last)) continue;//两行有王会在九宫格范围内重复... 44 dp[i][j][now]+=dp[i-1][j-num[now]][last];//同上一行的这种状态emm 方案数一样emm 45 } 46 } 47 for(i=0;i<(1<<n);i++) ans+=dp[n][k][i]; 48 printf("%lld", ans); 49 return 0; 50 }