狀壓dp(洛谷:互不侵犯)
阿新 • • 發佈:2020-09-21
在N×N的棋盤裡面放K個國王,使他們互不攻擊,共有多少種擺放方案。國王能攻擊到它上下左右,以及左上左下右上右下八個方向上附近的各一個格子,共8個格子
輸入格式
只有一行,包含兩個數N,K ( 1 <=N <=9, 0 <= K <= N * N)
輸出格式
所得的方案數
輸入輸出樣例
輸入 #13 2輸出 #
16
f[i][st][j]代表的是前i行第j列的二進位制數是st且有j個棋子的方案數
f[i][st][j]=Σf[i-1][st2][j-c(st2)]
#pragma GCC optimize(1) #pragmaGCC optimize(2) #pragma GCC optimize(3,"Ofast","inline") #include<cstring> #include<cstdio> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; template <typename Tp> void read(Tp &x){//read(n); x=0;char ch=1;int fh; while(ch!='-'&&(ch>'9'||ch<'0')){ ch=getchar(); } if(ch=='-'){ fh=-1;ch=getchar(); }else fh=1; while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+ch-'0';ch=getchar(); } x*=fh; } inline char read1()//字串讀入掛 { register char ch=getchar();while(ch<'A'||ch>'M')ch=getchar(); return ch; } const int maxn=1e6+100; int n,k; ll f[9][1<<9][100],ans; int c(int st){//返回st的二進位制表示中存了多少位1 int cnt=0; while(st){ if(st%2){ cnt++; } st/=2; } return cnt; } bool check1(int st){//判斷單行狀態st是否合法 for(int i=0;i+1<n;i++){ if((st & (1<<i)) && (st & (1<<(i+1)))) return false; } return true; } bool check2(int st,int st2){//判斷當前行st和他的上一行狀態st2之間的關係是否合法 for(int i=0;i<n;i++){ if(st & (1<<i)){ if(st2 & (1<<i)){ return false; } else if(i+1 < n && (st2 & (1<<(i+1)))){ return false; } else if(i-1 < n && (st2 & (1<<(i-1)))){ return false; } } } return true; } int main(){ cin>>n>>k; for(int i=0;i<n;i++){ for(int st=0;st < (1<<n);st++){ if(!check1(st)) continue; if(i==0) f[i][st][c(st)] = 1; else{ for(int j=c(st);j<=k;j++){ for(int st2=0;st2 < (1<<n);st2++){ if(!check1(st2)||!check2(st,st2)) continue; f[i][st][j]+=f[i-1][st2][j-c(st)]; } } } } } for(int st = 0;st < (1<<n); st++){ ans += f[n-1][st][k]; } cout<<ans<<endl; }