[SCOI2005]互不侵犯

[SCOI2005]互不侵犯

題目描述

在N×N的棋盤裏面放K個國王,使他們互不攻擊,共有多少種擺放方案。國王能攻擊到它上下左右,以及左上左下右上右下八個方向上附近的各一個格子,共8個格子。ios

注:數據有增強(2018/4/25)git

輸入輸出格式

輸入格式:函數

只有一行,包含兩個數N,K ( 1 <=N <=9, 0 <= K <= N * N)spa

輸出格式:code

所得的方案數get

輸入輸出樣例

輸入樣例#1:it

3 2

輸出樣例#1:io

16

\(n \le 9\)能夠看粗應該是個狀壓DPclass

因此就能夠高高興興個設狀態了stream

\(f[i][j][k]\)表示前\(i\) 行 最後一行狀態爲\(j\)\(k\)個的方案數

須要兩個函數判斷狀態合不合法還有放置的個數

inline int bitcnt(int x,int ans=0){
    for(;x;x&=(x-1),++ans);
    return ans;
}

用來判斷二進制中有幾個一(\(x\&=x-1\)是否是很熟悉沒錯就是今年初賽題)

inline bool pd(int x){
    return (((x<<1)&x)||((x>>1)&x));
}

這個用來判斷一個數合不合法(一個1左右不能有另外一個1)

而後就能夠列狀態轉移方程了

\(\displaystyle f[i][j][k]=\sum_{l與j合法}f[i-1][l][k-bitcnt(k)]\)

#include<iostream>
#include<cstdio>
using namespace std;
#define int long long 
int mian(){
    int s=0,f=1;char ch;
    while(!isdigit(ch=getchar()))(ch=='-')&&(f=-1);
    for(s=ch-'0';isdigit(ch=getchar());s=s*10+ch-'0');
    return s*f;
}
/*
子供の時の夢は言えますか
    その夢すら 溝に 舍てたのは
*/
int f[10][(1<<10)+1][100];
int n,m;
inline int bitcnt(int x,int ans=0){
    for(;x;x&=(x-1),++ans);
    return ans;
}
inline bool pd(int x){
    return (((x<<1)&x)||((x>>1)&x));
}
signed main(){
    n=mian(),m=mian();
    const int U = (1<<n)-1;
    f[0][0][0]=1;
    for(int i=1;i<=n;++i){
        for(int k=0;k<=U;++k){
            if(pd(k))continue;
            for(int l=0;l<=U;++l){
                if(pd(l))continue;
                if(l&k)continue;
                if((l>>1)&k)continue;
                if((l<<1)&k)continue;
                // cout<<k<<' '<<l<<endl;
                int c=bitcnt(k);
                for(int o=c;o<=m;++o)
                    f[i][k][o]+=f[i-1][l][o-c];
            }
        }
    }
    int ans=0;
    for(int i=0;i<=U;++i)ans+=f[n][i][m];
    cout<<ans<<endl;
    return 0;
}
相關文章
相關標籤/搜索