POJ1321(状压DP)

本文介绍了一种使用动态规划解决特定棋盘放置问题的方法。该算法能够在给定的n×n大小的棋盘上计算放置k个棋子的不同方式的数量,确保没有两个棋子处于同一行或同一列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

#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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值