zoukankan      html  css  js  c++  java
  • 【SCOI2005】互不侵犯

    题面

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

    输入:只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N

    分析

    数据规模极小+状态极多+网格题 == 状压dp

    套路:有放置的个数限制我们就需要在dp加一维。

    dp[i][j][k]表示扫到第i层,本层选择j状态,到目前为止总共用了k个国王的方案数

    还是需要预处理第一行。额外的,还需要预处理出每一种状态需用的国王数量(即计算二进制位有多少个1)

    #include<bits/stdc++.h>
    using namespace std;
    #define N 10
    #define M 1<<10
    #define ll long long
    ll dp[N][M][N*N],ok[M],need[M];
    ll n,k,mx,ans;
    
    int main()
    {
        cin>>n>>k;
        mx=(1<<n)-1;
        
        for(int i=0;i<=mx;i++)
        {
            int pos=i;
            while(pos)
            {
                if(pos%2)need[i]++;
                pos>>=1;//计算出每种状态需要多少King 
            }
        }
        
        for(int i=0;i<=mx;i++)
            if( ((i>>1)&i)==0 )
                ok[i]=1; 
        
        for(int i=0;i<=mx;i++)
            if( ok[i] & need[i]<=k)
                dp[1][i][need[i]]=1;
            
        for(int i=2;i<=n;i++)
            for(int j=0;j<=mx;j++)
                if(ok[j])
                    for(int s=0;s<=mx;s++)
                    {
                        if(s&j)continue;
                        if((s<<1)&j)continue;
                        if((s>>1)&j)continue;
                        for(int t=k;t>=need[j];t--)
                            dp[i][j][t]+=dp[i-1][s][t-need[j]];
                    }
        
        for(int i=0;i<=mx;i++)
            ans+=dp[n][i][k];
        cout<<ans;
    }
    “Make my parents proud,and impress the girl I like.”
  • 相关阅读:
    微博那点事(2)
    微博那点事(1)
    Netty断线重连
    高效沟通技巧
    Latex 公式在线可视化编辑器
    RPC框架原理与实现
    Java 静态代理与动态代理
    程序员主管之路(1)
    MarkDown 常用语法教程
    Solr vs. Elasticsearch谁是开源搜索引擎王者
  • 原文地址:https://www.cnblogs.com/NSD-email0820/p/9520474.html
Copyright © 2011-2022 走看看