• 【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.”
  • 相关阅读:
    java中的object类
    java中super的使用
    java中final的使用
    java中的继承初始化顺序
    java中的方法重写
    springMVC的流程
    dubbo与zookeeper
    java的几种常见数据结构
    集合框架之List和Set区别
    集合框架
  • 原文地址:https://www.cnblogs.com/NSD-email0820/p/9520474.html
Copyright © 2020-2023  润新知