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

    前言:一道状压DP的入门题(可惜我是个DP蒟蒻QAQ)

    ------------------

    题意简述:求在一个$n*n$的棋盘中放$k$个国王的方案数。注:当在一个格子中放入国王后,以此格为中心的九宫格的其他八个格子将不能放置国王。

    数据范围:$1leq nleq 9$,$1leq kleq n*n$。

    ------------------------------

    看到数据范围,不是$dfs$就是状压DP。这道题我们考虑状压DP。

    状压DP就是把某个阶段转换成二进制记录下来,一般用于数据范围较小的题目,状压因此得名。

    国王个数是一个限制条件,所以这是一个阶段。在状压DP中,我们一般考虑以行作为阶段。因为上一行的放置情况关系到这一行的放置情况,所以我们还要再用一维表示放置情况,这一维要用到状压。

    所以我们设$f[i][j][k]$为在前$i$行中放入$k$个国王,且这一行的摆放情况为$j$的方案数。摆放情况可以用$dfs$预先处理。

    考虑转移过程中的限制条件:

    如果$ sit[j]$ 与 $sit[k]=1 $,则表示上下相邻的格子都摆放了国王。

    如果$ (sit[j]<<1)$ 与 $sit[k]=1 $,则表示左上或右下摆放了国王。

    如果$ sit[j]$ 与 $(sit[k]<<1)=1 $,则表示右上或左下的格子摆放了国王。

    左右相邻的情况在$dfs$中即可排除。

    转移方程:$f[i][j][s]+=f[i-1][k][s-num[j]]$。$num[j]$表示放置情况为$j$时国王的放置个数。

    边界:$f[1][i][num[i]]=1$。

    其实貌似可以用滚动数组优化来省掉第一维,但我懒得写了。

    注意开$long long$。

    代码:

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    int n,m,cnt=0,ans=0;
    int sit[2005],num[2005];//预处理放置情况
    int f[10][2005][100];
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    void dfs(int pos,int sum,int node)
    {
        if (node>=n)
        {
            sit[++cnt]=pos;
            num[cnt]=sum;
            return;
        }
        dfs(pos,sum,node+1);//在此格不放入国王
        dfs(pos+(1<<node),sum+1,node+2);//在此格放入国王,此时要跳过相邻的格子。
    }
    signed main()
    {
        n=read(),m=read();
        dfs(0,0,0);
        for (int i=1;i<=cnt;i++) f[1][i][num[i]]=1;//边界
        for (int i=2;i<=n;i++)
            for (int j=1;j<=cnt;j++)
                for (int k=1;k<=cnt;k++)
                {
                    if (sit[j]&sit[k]) continue;
                    if ((sit[j]<<1)&sit[k]) continue;
                    if (sit[j]&(sit[k]<<1)) continue;
                    for (int s=m;s>=num[j];s--) f[i][j][s]+=f[i-1][k][s-num[j]];//转移
                }
        for (int i=1;i<=cnt;i++) ans+=f[n][i][m];
        printf("%ld",ans);
        return 0;
    }
  • 相关阅读:
    jquery 序列化form表单
    nginx for windows 安装
    nodejs idea 创建项目 (一)
    spring 配置 shiro rememberMe
    idea 2018 解决 双击shift 弹出 search everywhere 搜索框的方法
    redis 在windows 集群
    spring IOC控制反转和DI依赖注入
    redis 的安装
    shiro 通过jdbc连接数据库
    handlebars的用法
  • 原文地址:https://www.cnblogs.com/Invictus-Ocean/p/12716230.html
Copyright © 2011-2022 走看看