1. 程式人生 > >BZOJ1087: [SCOI2005]互不侵犯King(狀壓DP)

BZOJ1087: [SCOI2005]互不侵犯King(狀壓DP)

向上 har source while tput enable names define div

Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 5168 Solved: 3006
[Submit][Status][Discuss]

Description

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

Input

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

Output

  方案數。

Sample Input

3 2

Sample Output

16

HINT

Source

$f[i][j][k]$表示前$i$行,第$i$行的狀態為$j$,放了$k$個的方案

轉移的時候枚舉上一行的狀態是什麽

需要預處理出每一個狀態的國王數

// luogu-judger-enable-o2
// luogu-judger-enable-o2
#include<cstdio>
#define int long long 
using namespace std;
const int MAXN = 10;
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<22,stdin),p1==p2)?EOF:*p1++)
char buf[1<<22],*p1=buf,*p2=buf; inline int read() { char c=getchar();int x=0,f=1; while(c<0||c>9){if(c==-)f=-1;c=getchar();} while(c>=0&&c<=9){x=x*10+c-0;c=getchar();} return x*f; } int f[MAXN][1<<MAXN][MAXN*MAXN]; int N, K; int times[1
<<MAXN],can[1<<MAXN]; int calc(int x) { int num = 0; for(int i = 0;i < N; i++) if( x & (1 << i) ) num++; return num; } main() { #ifdef WIN32 freopen("a.in","r",stdin); #endif //printf("%d %d %d\n",0<<1,0>>1,0); N = read(), K = read(); int Max = (1 << N) - 1; for(int i = 0;i < Max; i++) times[i] = calc(i), can[i] = (i & (i>>1)) == 0 ? 1 : 0; f[0][0][0] = 1; for(int i = 1;i <= N; i++) for(int j = 0;j < Max; j++) if(can[j]) for(int k = 0;k < Max; k++) if(((j & k) == 0) && ((j & (k << 1)) == 0) && ((j & (k >> 1)) == 0)) for(int l = times[j]; l <= K; l++) f[i][j][l] += f[i-1][k][l - times[j]]; int ans = 0; for(int i = 0;i <= Max; i++) ans += f[N][i][K]; printf("%lld", ans); return 0; }

BZOJ1087: [SCOI2005]互不侵犯King(狀壓DP)