1. 程式人生 > >[SCOI2005]互不侵犯King

[SCOI2005]互不侵犯King

gre ont bsp mes .com des ans clas 之間

1087: [SCOI2005]互不侵犯King

Time Limit: 10 Sec Memory Limit: 162 MB Submit: 4255 Solved: 2458 [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 暴力枚舉鐵定TLE,考慮狀壓 設$dp[i][j][k]$表示前$i$行共取了$j$個且第$i$行取的情況為$k$的合法方案數 然後預處理出每種取法的棋子數,以及兩兩之間是否可行,轉移即可
#include <iostream>
using namespace std;
int n, k, Max;
int cnt[512] = {0};
bool s1[512], s2[512][512];
void init(){
    for(int i = 0; i <= Max; i++){
        if(i & (i >> 1
)){ s1[i] = false; continue; } s1[i] = true; for(int j = 0; j < 9; j++) if(i & (1 << j)) cnt[i]++; } for(int i = 0; i <= Max; i++) for(int j = i; j <= Max; j++) if((i & (j >> 1)) || (i & j) || ((i >> 1
) & j)) s2[i][j] = s2[j][i] = false; else s2[i][j] = s2[j][i] = true; } long long dp[10][100][512] = {0}; int main(){ cin >> n >> k; Max = (1 << n) - 1; init(); for(int i = 0; i <= Max; i++) if(s1[i] && cnt[1] <= k) dp[1][cnt[i]][i] = 1; for(int i = 1; i < n; i++) for(int j = 0; j <= Max; j++) if(s1[j]) for(int l = 0; l <= Max; l++) if(s1[l] && s2[j][l]) for(int m = cnt[j]; m + cnt[l] <= k; m++) dp[i + 1][m + cnt[l]][l] += dp[i][m][j]; long long ans = 0; for(int i = 0; i <= Max; i++) if(s1[i]) ans += dp[n][k][i]; cout << ans << endl; return 0; }

[SCOI2005]互不侵犯King