zoukankan      html  css  js  c++  java
  • BZOJ 1087: [SCOI2005]互不侵犯King

    传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=1087

    题意:每个点的八周不能放点,问放k个点一共有多少种方案

    题解:n特别小,所以可以想到状态压缩,因为在棋盘上面,所以根据经验应该是从上往下递推的,因为状态数比较多,我们先预处理一下整个棋盘

      于是:我们目前拥有的状态数是:有n行棋盘,有k个点,每一行和下一行的状态是相互相关的

      设dp[i][j][k]表示前i行放j个点时第i行的状态为k,那么我们最终的答案就是∑dp[n][k][i]   i->[0,1<<n]

    代码如下:

    #include <map>
    #include <set>
    #include <cmath>
    #include <ctime>
    #include <stack>
    #include <queue>
    #include <cstdio>
    #include <cctype>
    #include <bitset>
    #include <string>
    #include <vector>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    #define fuck(x) cout<<"["<<x<<"]";
    #define FIN freopen("input.txt","r",stdin);
    #define FOUT freopen("output.txt","w+",stdout);
    //#pragma comment(linker, "/STACK:102400000,102400000")
    using namespace std;
    typedef long long LL;
    typedef pair<int, int> PII;
    const int maxn = 1e5+5;
    const int INF = 0x3f3f3f3f;
    const int MOD = 1e9+7;
    int n,k,num[1000];
    LL dp[10][1000][1000];
    bool flag[1000];
    LL ans;
    /*dp[i][j][k]为前i行已经放了j个国王并且第i行的状态为k(二进制)的方案数,
    那么dp[i][j][k] = Σdp[i-1][j - num[k]][p],
    其中num数组记录着一行为状态k的放的国王的数目,p为上一行符合要求的状态*/
    void init(){
        for(int i=0;i<(1<<n);i++){
            //num:第i行可以放的数目
            if(!(i&(i<<1))){
                cout<<i<<" "<<(i<<1)<<" "<<(i&(i<<1))<<endl;
                flag[i]=1;
                int t=i;
                while(t){
                    num[i]+=(t&1);
                    t>>=1;
                }
                //当前状态i放数量num【i】的方法
                dp[1][num[i]][i]=1;
            }
        }
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
        FIN
    #endif
        scanf("%d%d",&n,&k);
        init();
        for(int i=2;i<=n;i++){//控制行数
            for(int j=0;j<=k;j++){//控制国王的个数
                for(int now=0;now<(1<<n);now++){//控制当前状态
                    if(!flag[now]) continue;
                    if(num[now]>j) continue;
                    for(int last=0;last<(1<<n);last++){//控制上一个状态
                        if(!flag[last]) continue;
                        //如果存在攻击范围重叠的情况的话 跳过
                        if((last&now)||((now<<1)&last)||(now>>1)&last) continue;
                        //
                        dp[i][j][now]+=dp[i-1][j-num[now]][last];
                     }
                }
            }
        }
        for(int i=0;i<(1<<n);i++){
            ans+=dp[n][k][i];
        }
        printf("%lld
    ",ans);
    }
    View Code
    每一个不曾刷题的日子 都是对生命的辜负 从弱小到强大,需要一段时间的沉淀,就是现在了 ~buerdepepeqi
  • 相关阅读:
    MySQL 数据库常用命令
    HTML常用标签介绍
    浏览器 返回状态码汇总
    Mysql常用的三种数据库引擎比较
    系统常用端口大全
    nginx入门与实战
    Linux系统基础优化及常用命令
    python开发之virtualenv与virtualenvwrapper讲解
    常用服务安装部署
    远程连接Linux
  • 原文地址:https://www.cnblogs.com/buerdepepeqi/p/9551633.html
Copyright © 2011-2022 走看看