Loading

SGU 223 国王 状压DP

在 n×的棋盘上放 kk 个国王,国王可攻击相邻的 88 个格子,求使它们无法互相攻击的方案总数。

状压DP是一种比较暴力的DP。

首先dp[i][j][k]表示前i行放置k个国王,且当前行状态是j的方案数。

转移方程 dp[i][j][k] = dp[i - 1][m][k - sum[k]]

sum[k]表示第k个合法状态的放置的国王个数。

什么叫第k个合法状态。由于每行的放置规则是有限的,所以可以预处理出合法状态记录到sum里和一个st数组表示第i个合法状态的国王个数。

最后只要求 1 <= i <= cnt 下dp[n][i][k] cnt是合法状态数

ll dp[12][1 << 10 + 5][105];
int st[1 << 10 + 5];
int sum[1 << 10 + 5];

bool check(int x, int y) {
    if ((x & y) || (x & (y << 1)) || (x & (y >> 1))) return false;
    return true;
}

int main() {
    int n = readint();
    int k = readint();
    int cnt = 0;
    for (int i = 0; i < 1 << n; i++) {
        if (!(i & (i << 1))) {
            st[++cnt] = i;
            sum[cnt] = bitcount(i);
        }
    }
    for (int i = 1; i <= cnt; i++) dp[1][i][sum[i]] = 1;
    for (int i = 2; i <= n; i++) 
        for (int j = 1; j <= cnt; j++)
            for (int m = sum[j]; m <= k; m++)
                  for (int jj = 1; jj <= cnt; jj++)
                      if (check(st[j], st[jj])) dp[i][j][m] += dp[i - 1][jj][m - sum[j]];
    ll sum = 0;
    for (int i = 1; i <= cnt; i++) sum += dp[n][i][k];  
    Put(sum);
}

 

posted @ 2020-08-11 19:23  MQFLLY  阅读(274)  评论(0编辑  收藏  举报