1. 程式人生 > >[Bzoj1083][SCOI2005]互不侵犯king(狀壓dp)

[Bzoj1083][SCOI2005]互不侵犯king(狀壓dp)

pan main ostream output mit c代碼 gree 包含 ems

1087: [SCOI2005]互不侵犯King


Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 4595 Solved: 2664
[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

分析:


老套路,預先處理出一行內合法方案,減少枚舉數。

定義狀態f[i][j][k]第i行,狀態為j,目前一共放了k個國王,轉移走就行了。

AC代碼:


# include <iostream>
# include <cstdio>
# include <cstring>
using namespace std;
const int N = 1 << 9; int cnt,state[102],num[102],P,n,c; long long f[10][102][102]; int lowbit(int r){ return r & -r; } void work(){ for(int i = 0;i < P;i++){ int pre = lowbit(i),r = i - pre;bool flag = true; while(r){ if(lowbit(r) / pre <= 2){ flag
= false;break; } pre = lowbit(r);r -= pre; } if(flag)state[++cnt] = i; } for(int i = 1;i <= cnt;i++){ int r = state[i]; while(r){ r -= lowbit(r); num[i]++; } } } int main(){ scanf("%d %d",&n,&c);P = 1 << n; work(); f[0][1][0] = 1LL; for(int i = 1;i <= n;i++){ for(int j = 1;j <= cnt;j++){ for(int k = 1;k <= cnt;k++){ for(int l = 0;l <= c;l++){ if(state[j] & state[k])continue; if((state[j] >> 1) & state[k])continue; if((state[j] << 1) & state[k])continue; f[i][j][l + num[j]] += f[i - 1][k][l]; } } } } long long ans = 0; for(int i = 1;i <= cnt;i++){ ans += f[n][i][c]; } printf("%lld\n",ans); }

[Bzoj1083][SCOI2005]互不侵犯king(狀壓dp)