• 【SCOI2005】【BZOJ1087】互不侵犯King(状压dp)


    problem

    • 在N×N的棋盘里面放K个国王
    • 每个国王会攻击它周围的一圈共8个格子
    • 使他们互不攻击,共有多少种摆放方案
    • N <= 9

    solution

    • 用01串表示某一行放置的情况
    • 首先枚举当前做到第几行,以及当前一共放了几颗棋子。
    • 于是状态f[i][j][k]表示到第i行,一共放j个棋子(包括这之前的),且第i行的状态是k的方案数。
    • 再考虑转移。这一行肯定是由上一行的状态转移过来的,那么我们可以再枚举上一行的状态。
    • 很自然的,发现这会超时。每次枚举一种状态就需要2^9,两重循环已经快爆掉了!我们可以发现一件事情。比如n=5,我们每次枚举到的11111,11011,10111,01011这些状态都是无效的。那么我们可以先预处理一下对于每一行的所有可行的状态(就是不能有连续的1)。
    • 这样的效率仍然不高——我们还可以对于每种可行的状态i,j,预处理i和j是否能够相邻,这样我们在DP的时候,就可以O(1)来转移了。(这里也可以不预处理,每次直接判断ij能否相邻也可。)

    最后,记得开long long。

    codes

    #include<iostream>
    using namespace std;
    const int maxn = 512;
    typedef long long LL;
    int c1[maxn], cnt[maxn], c2[maxn][maxn];
    LL ans, f[10][100][maxn];
    int main(){
        int n, m;
        cin>>n>>m;
        int all = (1<<n)-1;
        for(int i = 0; i <= all; i++){
            if((i&(i>>1))==0){
                c1[i] = 1;
                for(int x = i; x; x >>= 1) cnt[i]+= (x&1);
            }
        }
        for(int i = 0; i <= all; i++)if(c1[i])f[1][cnt[i]][i] = 1;
        for(int i = 1; i < n; i++){
            for(int j = 0; j <= all; j++)if(c1[j]){
                for(int k = 0; k <= all; k++)if(c1[k]){
                    if(((j&k)==0)&&((j&(k>>1))==0)&&((j&(k<<1))==0)){
                        for(int p = cnt[j]; p+cnt[k]<=m; p++)
                            f[i+1][p+cnt[k]][k] += f[i][p][j];
                    }
                }
            }
        }
        for(int i = 0; i <= all; i++)ans += f[n][m][i];
        cout<<ans<<"
    ";
        return 0;
    }
  • 相关阅读:
    新手ui设计师必备——切图规范
    django1.4日志模块配置及使用
    linux chmod命令和chown命令
    python log
    python curses使用
    css3中变形与动画(三)
    django静态文件配置
    centos7 apache httpd安装和配置django项目
    apache httpd服务器403 forbidden的问题
    centos7 mysql数据库安装和配置
  • 原文地址:https://www.cnblogs.com/gwj1314/p/9444821.html
Copyright © 2020-2023  润新知