链接: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。
表示第
行状态为
的方案数,第二维的
用二进制01表示这一行的所有位置的状态,0表示没人,1表示有人。
从上一行递推到下一行,首先当前这一行上状态
要满足不相邻,即 (S & (S >> 1)) == 0
,而且还要满足这一行上的地形条件(0不能站人,1才能站人),即 (S & a[i]) == S
,这里
也是用二进制01表示了一整行的状态,需要提前处理。
当这个状态
满足上述条件后,就可以从上一行的所有状态
转移到当前状态
,需要满足同一列上不能同时有人,即 (S & S') == 0
,
。
code
#include <bits/stdc++.h>
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;
}