<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 }
点击查看丑陋の代码&注释
原文地址:https://www.cnblogs.com/pile8852/p/9291718.html