BZOJ1087[SCOI2005]互不侵犯——狀壓DP
阿新 • • 發佈:2018-07-12
scanf times space 輸入 mes 枚舉 style std 一行
題目描述
在N×N的棋盤裏面放K個國王,使他們互不攻擊,共有多少種擺放方案。國王能攻擊到它上下左右,以及左上
左下右上右下八個方向上附近的各一個格子,共8個格子。
輸入
只有一行,包含兩個數N,K ( 1 <=N <=9, 0 <= K <= N * N)
輸出
方案數。
樣例輸入
3 2樣例輸出
16 n<=9,顯然是狀壓dp,定義狀態f[i][j][k]表示枚舉到第i行,狀態為j,前i行總共放了k個國王的方案數。搜索出一行符合的所有狀態,枚舉當前行和上一行的狀態,判斷是否沖突,然後f[i][j][l]+=f[i-1][k][l-t[j]]轉移即可。最後答案是∑f[n][j][m]#include<queue> #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; long long f[12][2000][200]; int cnt; int n,m; int s[2000]; int t[2000]; long long ans; void dfs(int x,int y,int sum) { if(y>=n) { s[++cnt]=x; t[cnt]=sum; return ; } dfs(x,y+1,sum); dfs(x|(1<<y),y+2,sum+1); } int main() { scanf("%d%d",&n,&m); dfs(0,0,0); for(int i=1;i<=cnt;i++) { f[1][i][t[i]]=1; } for(int i=2;i<=n;i++) { for(int j=1;j<=cnt;j++) { for(int k=1;k<=cnt;k++) { if(s[j]&s[k]) { continue; } if((s[j]<<1)&s[k]) { continue; } if(s[j]&(s[k]<<1)) { continue; } for(int l=t[j];l<=m;l++) { f[i][j][l]+=f[i-1][k][l-t[j]]; } } } } for(int j=1;j<=cnt;j++) { ans+=f[n][j][m]; } printf("%lld",ans); }
BZOJ1087[SCOI2005]互不侵犯——狀壓DP