zoukankan      html  css  js  c++  java
  • 洛谷——P1896 [SCOI2005]互不侵犯

    P1896 [SCOI2005]互不侵犯

    状压DP入门题

    状压DP一般需要与处理状态是否合法,节省时间

    设定状态dp[i][j][k]表示第i行第j个状态选择国王数为k的方案数

    $dp[i][j][num[j]+p]+=dp[i-1][k][p]$

    转移方程如上,表示第i行第j个状态国王数量为$num[j]+p$由上一行第k个状态的p个国王转移而来

    状压DP的一般套路不就是将数的二进制表示成状态,如1010(10)10这个数就表示第一个位置放,第二个不放,以此类推

    预处理:判断这一行的国王是否冲突,i&(i<<1) 想象成二进制,将i左移一位与i比较判断国王是否相邻

    如何判断上下两行国王是否冲突呢?

    x&y判断上下是否冲突

    x&(y<<1) 判断左上右下是否冲突

    x&(y>>1) 判断右上左下是否冲突

    #include<bits/stdc++.h>
    
    #define LL long long
    using namespace std;
    
    LL MAX,n,m,dp[20][1005][400],can[5000],num[5000],tot,ans;
    
    LL getsum(LL x){
        LL cnt=0;
        while(x) cnt+=(x&1),x>>=1;
        return num[tot]=cnt;
    }
    
    int main()
    {
        scanf("%lld%lld",&n,&m);
        MAX=(1<<n)-1;
        for(LL i=0;i<=MAX;i++) {
            if(!(i&(i<<1))) can[++tot]=i,dp[1][tot][getsum(i)]=1;
        }
        for(LL i=2;i<=n;i++){
            for(LL j=1;j<=tot;j++){
                LL x=can[j];
                for(LL k=1;k<=tot;k++){
                    LL y=can[k];
                    if((x&y)||(x&(y<<1))||(x&(y>>1))) continue;
                    for(LL p=0;p<=m;p++)
                        dp[i][j][num[j]+p]+=dp[i-1][k][p];
                }
            }
        }
        for(LL i=1;i<=tot;i++) ans+=dp[n][i][m];
        printf("%lld
    ",ans);
        return 0;
    } 
  • 相关阅读:
    结构~函数~输入输出
    常用缀名
    结构
    枚举
    int argc char*argv[]
    字符串的操作
    字符串函数#include<string.h>
    指针的应用
    2019.1.25~2019.1.30学习总结
    v-for
  • 原文地址:https://www.cnblogs.com/song-/p/9621285.html
Copyright © 2011-2022 走看看