[SCOI2005]互不侵犯King
阿新 • • 發佈:2017-08-27
gre ont bsp mes .com des ans clas 之間
3 2
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
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