NC15034 德玛西亚万岁(状压dp)

链接:https://ac.nowcoder.com/acm/problem/15034

题目描述

德玛西亚是一个实力雄厚、奉公守法的国家,有着功勋卓著的光荣军史。
这里非常重视正义、荣耀、职责的意识形态,这里的人民为此感到强烈自豪。
有一天他们想去制裁邪恶的比尔吉沃特,于是派遣了自己最优秀的战士。
结果比尔吉沃特领土太小,只有长为n宽为m共计n*m块土地,其中有些土
地标记为0表示为高山峻岭或者深海湖泊,英雄们无法在其中站立,只有标
记为1的土地才能容纳一个英雄。德玛西亚的英雄们战斗时有一个特点,他
们不希望队友站在自己旁边显得很暧昧。请问最多能有多少种安排德玛西
亚英雄的方法?

输入描述:

输入包含多组测试数据;
每组数据的第一行包含2个整数n和m (n <= 12, m <= 12 ),之间用空格隔开;
接下来的n行,每行m个数,表示n*m的比尔吉沃特领土。

输出描述:

输出一个整数n代表安排应用的方法。
(答案取膜100000000)

输入

3 3
1 1 1
0 1 1
1 0 0

输出

24


solution

直觉动态规划,一行一行递推,看数据范围猜状压dp。 d p [ i ] [ S ] dp[i][S] dp[i][S] 表示第 i i i 行状态为 S S S 的方案数,第二维的 S S S 用二进制01表示这一行的所有位置的状态,0表示没人,1表示有人。
从上一行递推到下一行,首先当前这一行上状态 S S S 要满足不相邻,即 (S & (S >> 1)) == 0,而且还要满足这一行上的地形条件(0不能站人,1才能站人),即 (S & a[i]) == S,这里 a [ i ] a[i] a[i] 也是用二进制01表示了一整行的状态,需要提前处理。
当这个状态 S S S 满足上述条件后,就可以从上一行的所有状态 S ′ S' S 转移到当前状态 S S S,需要满足同一列上不能同时有人,即 (S & S') == 0 d p [ i ] [ S ] = ∑ d p [ i − 1 ] [ S ′ ] dp[i][S]=\sum{dp[i-1][S']} dp[i][S]=dp[i1][S]

code

#include 
using namespace std;
const int mod = 100000000;
int n, m;
int a[15];
int dp[15][1 << 15]; //第二维表示这一行的所有位置的状态,用二进制01表示
int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    while (cin >> n >> m) {
        for (int i = 1; i <= n; i++) {
            a[i] = 0;
            for (int j = 0; j < m; j++) {
                int x;
                cin >> x;
                a[i] = (a[i] << 1) | x; //转换为二进制状态位
            }
        }
        memset(dp, 0, sizeof(dp));
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j < (1 << m); j++) {
                if ((j & (j >> 1)) == 0 && (j & a[i]) == j) {
                    if (i == 1)
                        dp[i][j] = 1;
                    else {
                        for (int k = 0; k < (1 << m); k++) {
                            if ((j & k) == 0) {
                                dp[i][j] = (dp[i][j] + dp[i - 1][k]) % mod;
                            }
                        }
                    }
                }
            }
        }
        int ans = 0;
        for (int i = 0; i < (1 << m); i++)
            ans = (ans + dp[n][i]) % mod;
        cout << ans << endl;
    }
    return 0;
}

你可能感兴趣的:(牛客练习,动态规划)