zoukankan      html  css  js  c++  java
  • SCOI2005 互不侵犯(状压DP)

    SCOI2005 互不侵犯(状压DP)

    题目大意

    (N×N)的棋盘里面放(K)个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。

    Input

    一行(N,K)

    Output

    方案数

    Solution

    状态压缩DP基础
    状压和二进制有着不可割舍的联系
    一帮情况下,(我)习惯把状态抽象成一维
    并且用二进制表示,然后再去想怎么压缩状态

    比如互不侵犯这个题
    根据题目中给出的变量
    直接定义dp[i][j][k]表示
    第i行在状态为j时,共用了k个国王的方案数
    那么如何判断上下左右有没有重复呢
    这就用到二进制的运算&
    然后预处理所有不必转移的状态和所有的状态
    所有状态是指n位数的所有状态

    例如n=3
    所有状态就是
    000,001,010,011,100,101,110,111
    

    num数组记录当前状态的国王数量
    第一能够减小常数
    第二作为状态转移的初始状态

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #define int long long
    using namespace std;
    
    inline int read(){
        int x = 0, w = 1;
        char ch = getchar();
        for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') w = -1;
        for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
        return x * w;  
    }
    
    const int maxn = 520;
    int dp[20][maxn][maxn];
    int s[maxn], num[maxn];
    int cnt, n, k;
    
    inline void pre(){
        cnt = 0;
        for(int i = 0; i < (1 << n); i++){
            if(i & (i << 1)) continue;
            int sum = 0;
            for(int j = 0; j < n; j++)
                if(i & (1 << j)) ++sum;
            s[++cnt] = i;   
            num[cnt] = sum;
        }
    }
    
    signed main(){
        n = read(), k = read();
        pre();
        dp[0][1][0] = 1;
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= cnt; j++)
                for(int l = 0; l <= k; l++)
                if(l >= num[j]){
                    for(int t = 1; t <= cnt; t++){
                        if(!(s[t] & s[j]) && !(s[t] & s[j] << 1) && !(s[t] & s[j] >> 1))
                            dp[i][j][l] += dp[i - 1][t][l - num[j]];
                    }
                }
        int ans = 0;
        for(int i = 1; i <= cnt; i++)
            ans += dp[n][i][k];
        cout << ans << '
    ';
        return 0;
    }
    
  • 相关阅读:
    hdu 2222 Keywords Search 模板题
    AC自动机 (模板)
    7. 通过鼠标右键改变视角
    NGUI所见即所得之UIAtlasMaker , UIAtlas (2)
    6. 通过鼠标滑轮控制“镜头远近”
    5. Unity脚本的执行顺序
    4. 在Inspector面板中显示类中变量+ 拓展编辑器
    NGUI 的使用教程与实例(入门)(1 )
    1. 通过移动鼠标旋转摄像机观察模型
    C#面试题
  • 原文地址:https://www.cnblogs.com/rui-4825/p/12686200.html
Copyright © 2011-2022 走看看