POJ1321(状压DP)

数据比较小,怎么暴力都行。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 1<<8
#define maxm 8111111

int n, kk;
char mp[11][11];
long long dp[11][maxn]; //放到第i行 状态为j 已经放置k个棋子的种数
int board[11]; // 第i行的状态
int num[maxn], state[maxn], cnt;

int get (int x) { //x二进制1的个数
    int ans = 0;
    while (x) {
        if (x&1)
            ans++;
        x >>= 1;
    }
    return ans;
}

bool ok (int x) {
    if (x == 0)
        return 1;
    for (int i = 1; i < (1<<n); i <<= 1) {
        if (x == i)
            return 1;
    }
    return 0;
}

int main () {
    //freopen ("in", "r", stdin);
    for (int i = 0; i < maxn; i++) {
        num[i] = get (i);
    }
    cnt = 0; state[++cnt] = 0;
    for (int i = 0; i <= 7; i++) {
        state[++cnt] = (1<<i);
    }
    while (scanf ("%d%d", &n, &kk) == 2) {
        if (n == kk && n == -1)
            break;
        for (int i = 0; i < n; i++) {
            scanf ("%s", &mp[i]);
            board[i] = 0;
            for (int j = 0; j < n; j++) {
                board[i] = (board[i]<<1) + (mp[i][j] == '#' ? 0 : 1);
            }
        }
        memset (dp, 0, sizeof dp);
        for (int i = 1; i <= cnt && state[i] < (1<<n); i++) {
            if (board[0]&state[i])
                continue;
            dp[0][state[i]] = 1;
        }
        for (int i = 1; i < n; i++) {
            for (int j = 0; j < (1<<n); j++) {
                for (int y = 1; y <= cnt && state[y] < (1<<n); y++) {
                    int k = state[y];
                    if (j&k)
                        continue;
                    if (board[i]&k)
                        continue;
                    dp[i][k^j] += dp[i-1][j];
                }
            }
        }
        long long ans = 0;
        for (int i = 0; i < (1<<n); i++) {
            if (num[i] == kk)
                ans += dp[n-1][i];
        }
        printf ("%lld\n", ans);
    }
    return 0;
}


你可能感兴趣的:(POJ1321(状压DP))