acwing状态压缩
小国王(井字型DP)

思路

样例输入:
3 2
样例输出:
16
代码模板:
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long LL;
const int N = 12, M = 1 << 10, K = 110;
int n, m;
vector<int> state;
int cnt[M];
vector<int> head[M];
LL f[N][K][M];
bool check(int state)
{
for (int i = 0; i < n; i ++ )
if ((state >> i & 1) && (state >> i + 1 & 1))
return false;
return true;
}
int count(int state)
{
int res = 0;
for (int i = 0; i < n; i ++ ) res += state >> i & 1;
return res;
}
int main()
{
cin >> n >> m;
for (int i = 0; i < 1 << n; i ++ )
if (check(i))
{
state.push_back(i);
cnt[i] = count(i);
}
for (int i = 0; i < state.size(); i ++ )
for (int j = 0; j < state.size(); j ++ )
{
int a = state[i], b = state[j];
if ((a & b) == 0 && check(a | b))
head[i].push_back(j);
}
f[0][0][0] = 1;
for (int i = 1; i <= n + 1; i ++ )
for (int j = 0; j <= m; j ++ )
for (int a = 0; a < state.size(); a ++ )
for (int b : head[a])
{
int c = cnt[state[a]];
if (j >= c)
f[i][j][a] += f[i - 1][j - c][b];
}
cout << f[n + 1][m][0] << endl;
return 0;
}
玉米田(十字型DP)

样例输入:
2 3
1 1 1
0 1 0
样例输出:
9
代码模板:
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 14, M = 1 << 12, mod = 1e8;
int n, m;
int w[N];
vector<int> state;
vector<int> head[M];
int f[N][M];
bool check(int state) //判断是否存在相邻土地种了玉米
{
for (int i = 0; i + 1 < m; i ++ )
if ((state >> i & 1) && (state >> i + 1 & 1))
return false;
return true;
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i ++ )
for (int j = 0; j < m; j ++ )
{
int t;
cin >> t;
w[i] += !t * (1 << j);
}
for (int i = 0; i < 1 << m; i ++ ) //行相邻之间没有连续的1状态
if (check(i))
state.push_back(i);
for (int i = 0; i < state.size(); i ++ ) //并且一列没有相邻的1的所有状态
for (int j = 0; j < state.size(); j ++ )//预处理上一行状态为a下一行状态为b且合法的所有状态
{
int a = state[i], b = state[j];
if (!(a & b))
head[i].push_back(j);
}
f[0][0] = 1;
for (int i = 1; i <= n + 1; i ++ )
for (int j = 0; j < state.size(); j ++ )
if (!(state[j] & w[i])) //如果状态j与土地本身冲突(即不合法),则continue
for (int k : head[j])
f[i][j] = (f[i][j] + f[i - 1][k]) % mod;
cout << f[n + 1][0] << endl; //小技巧 不用遍历最后一行
return 0;
}
炮兵阵地(十字形DP)

样例输入:
5 4
PHPP
PPHH
PPPP
PHPP
PHHP
样例输出:
6
代码模板:
#include <iostream>
#include <vector>
using namespace std;
const int N = 110, M = 10, S = 1 << M;
int n, m;
int f[2][S][S];//滚动数组
vector<int> state;
int g[N];
int cnt[S];
// 检查状态是否合法
bool check(int s) {
for (int i = 0; i < m; i ++ )
if ((s >> i & 1) && ((s >> i + 1 & 1) || (s >> i + 2 & 1))) return false;
return true;
}
//检查状态s中有多少个1,即有多少个位置摆了炮兵
int count(int s) {
int cnt = 0;
while (s) {
cnt += s & 1;
s >>= 1;
}
return cnt;
}
int main() {
cin >> n >> m;
//g[i]表示第i行的0(P)和1(H)的位置摆放情况
for (int i = 0; i < n; i ++ ) {
for (int j = 1; j <= m; j ++ ) {
char c;
cin >> c;
if (c == 'H') g[i] += 1 << (m - j);
}
}
//合法位置的集合;
for (int i = 0; i < 1 << m; i ++ ) {
if (check(i)) {
state.push_back(i);
cnt[i] = count(i);
}
}
for (int i = 0; i <= n + 1; i ++ )
for (int j = 0; j < state.size(); j ++ )
for (int k = 0; k < state.size(); k ++ )
for (int u = 0; u < state.size(); u ++ ) {
//a 表示 i - 1行状态, b表示第i行状态, c表示第i - 2行状态
int a = state[j], b = state[k], c = state[u];
if ((a & b) || (a & c) || (b & c)) continue;//列
if (g[i] & b) continue;
f[i & 1][a][b] = max(f[i & 1][a][b], f[i - 1 & 1][c][a] + cnt[b]);
}
cout << f[n + 1 & 1][0][0] << endl;
return 0;
}

浙公网安备 33010602011771号