洛谷 P1896 [SCOI2005]互不侵犯(状压DP)

题目链接:https://www.luogu.com.cn/problem/P1896

状压DP,一般都是枚举行,然后枚举每一行的状态(二进制),每一行的最大状态也就是1<<(len)-1,然后重点便是一些二进制的操作。

本题将每一行的方案二进制压成一维。然后只需二进制判断同一行中左右是否冲突,与上一行是否冲突,注意判断是否冲突的二进制方法。

在dp[][][]中,第一维表示行数,第二维表示当前行的状态,第三维表示到当前为止用了多少个国王。然后暴力转移即可。

AC代码:

 1 #include<cstdio>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N=1000+10;
 5 ll dp[10][N][100];//行 状态 限定 
 6 int state[N];
 7 int cul(int x){
 8     int ans=0;
 9     while(x){
10         if(x&1) ans++;
11         x>>=1;
12     }
13     return ans;
14 }
15 int judge(int x,int y){
16     if(x&y) return 0;
17     if(x&(y>>1)) return 0;
18     if(x&(y<<1)) return 0;
19     return 1;
20 }
21 int main(){
22     int n,m;
23     scanf("%d%d",&n,&m);
24     int maxstate=(1<<n);
25     for(int i=0;i<maxstate;i++) state[i]=((i&(i<<1))==0&&(i&(i>>1))==0);//判断一行中每一个状态左右是否满足 
26     for(int j=0;j<maxstate;j++) if(state[j]&&cul(j)<=m) dp[1][j][cul(j)]=1;//处理第一行 
27     for(int i=2;i<=n;i++){
28         for(int j=0;j<maxstate;j++){//当前一行的状态 
29             if(state[j]==0) continue;
30             for(int k=0;k<maxstate;k++){//上一行的状态 
31                 if(state[k]==0||judge(j,k)==0) continue;
32                 for(int l=m;l>=cul(j);l--) dp[i][j][l]+=dp[i-1][k][l-cul(j)];//l枚举当前总共使用过的国王
33             }
34         }
35     }
36     ll ans=0;
37     for(int i=0;i<maxstate;i++) ans+=dp[n][i][m];//显然 
38     printf("%lld
",ans);
39     return 0;
40 }
AC代码
原文地址:https://www.cnblogs.com/New-ljx/p/12493312.html