car

好,這又是一道狀壓DP題。ide

題意:給你n * n的棋盤,有m個點不能放東西,要放k個車上去,問有多少種方案可使它們不互相攻擊。spa

n <= 18code

而後就一眼狀壓了。blog

設f[i][j]表示前i行,已經放車的列狀態是j的方案數。io

而後有兩種轉移方案。我比較喜歡刷表法。event

每次枚舉i,而後枚舉j,而後枚舉i + 1行在哪列放車。class

初始狀態是f[0][0] = 1,最後統計f[n][x]cli

時間複雜度n²lognsed

 1 #include <cstdio>
 2 
 3 const int N = 20, MO = 1e9 + 7;
 4 
 5 int f[N][1 << N];
 6 bool vis[N][N];
 7 
 8 inline bool check(int s, int k) {
 9     int cnt = 0;
10     while(s) {
11         cnt += (s & 1);
12         if(cnt > k) {
13             return 0;
14         }
15         s >>= 1;
16     }
17     return cnt == k;
18 }
19 
20 int main() {
21     //freopen("car.in", "r", stdin);
22     //freopen("car.out", "w", stdout);
23     int n, m, k;
24     scanf("%d%d%d", &n, &m, &k);
25     if(k > n) {
26         printf("0");
27         return 0;
28     }
29     for(int i = 1, x, y; i <= m; i++) {
30         scanf("%d%d", &x, &y);
31         vis[x][y - 1] = 1;
32     }
33 
34     f[0][0] = 1;
35 
36     int lm = 1 << n;
37     for(int i = 0; i < n; i++) {
38         for(int j = 0; j < lm; j++) {
39             f[i + 1][j] += f[i][j];
40             f[i + 1][j] %= MO;
41             for(int p = 0; p < n; p++) {
42                 if(((j >> p) & 1) || vis[i + 1][p]) {
43                     continue;
44                 }
45                 (f[i + 1][j | (1 << p)] += f[i][j]) %= MO;
46             }
47         }
48     }
49 
50     int ans = 0;
51     for(int i = 0; i < lm; i++) {
52         if(check(i, k)) {
53             ans += f[n][i];
54             ans %= MO;
55         }
56     }
57     printf("%d", ans);
58     return 0;
59 }
AC代碼
相關文章
相關標籤/搜索