《算法进阶指南》 DP状态压缩 炮兵阵地
炮兵攻击范围为两格,之枚举两行的状态不够。必须前两行转移给第三行。但这样210*2102^10会超时,去掉每行炮兵与高原冲突的状态,去掉每行可以互相攻击到的状态,剩余状态数<=60满足复杂度。
如果开1e3(210)*(210)的空间会超内存,还得使用滚动数组。对应行数取模3即可。
值得注意的细节,将地形状态也压缩,令高原为1。这样只要 地形状态&炮兵状态 就能检查是否有冲突。假如当前炮兵状态为st,(st>>1)&st||(st>>2)&st,能够检查炮兵直接距离是否大于2。这样完全不需要按位遍历每一个状态,实现也很简单。
using namespace std;
// #define int long long
#define INF 1e9
#define endl '\n'
int n, m;
int fl[102][12];
int f[102][2003];
vector<int> allst[102];
void getvalidst()
{
for (int line = 1; line <= n; line++)
{
for (int i = 0; i < (1 << m); i++)
{
int cnt = 2;
int ok = 1;
for (int j = 0; j < m; j++)
{
if (((i >> j)) & 1)
{
if (fl[line][j + 1] == 0)
{
ok = 0;
break;
}
if (cnt >= 2)
{
cnt = 0;
}
else
{
ok = 0;
break;
}
}
else
{
cnt++;
}
}
if (ok == 1)
{
allst[line].push_back(i);
}
}
}
}
bool oktrans(int st1, int st2, int st3)
{
int ok = 1;
for (int i = 0; i < m; i++)
{
int zwei1 = (st1 >> i) & 1;
int zwei2 = (st2 >> i) & 1;
int zwei3 = (st3 >> i) & 1;
if (zwei1 + zwei2 + zwei3 > 1)
{
ok = 0;
}
}
return ok;
}
int onenum(int st)
{
int cnt = 0;
for (int i = 0; i < m; i++)
{
cnt += (st >> i) & 1;
}
return cnt;
}
void solve()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
char tmp;
cin >> tmp;
if (tmp == 'P')
{
fl[i][j] = 1;
}
else
{
fl[i][j] = 0;
}
}
}
getvalidst();
allst[0].push_back(0);
for (int i = 0; i < allst[1].size(); i++)
{
f[1][allst[1][i]] = onenum(allst[1][i]);
}
for (int i = 2; i <= n; i++)
{
for (int ind1 = 0; ind1 < allst[i - 2].size(); ind1++)
{
for (int ind2 = 0; ind2 < allst[i - 1].size(); ind2++)
{
for (int ind3 = 0; ind3 < allst[i].size(); ind3++)
{
int st1 = allst[i - 2][ind1], st2 = allst[i - 1][ind2], st3 = allst[i][ind3];
if (oktrans(st1, st2, st3))
{
f[i][st3] = max(f[i][st3], f[i - 2][st1] + onenum(st2) + onenum(st3));
}
}
}
}
}
int ans = 0;
for (int i = 0; i < allst[n].size(); i++)
{
ans = max(ans, f[n][allst[n][i]]);
}
cout << ans << endl;
}
signed main()
{
#ifdef LOCAL_ENV
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(false), cin.tie(0);
int T = 1;
// cin >> T;
for (int i = 1; i <= T; i++)
{
solve();
}
return 0;
}
收获:
1.状态压缩常见为可用n进制表示当前状态,前后两个阶段的状态需要“匹配”上才能转移。
2.状态压缩可以提前处理一个阶段的状态,将已经不合法的状态去除,减少阶段间转移的复杂度。
3.状态压缩一些位运算技巧。用&查重。

浙公网安备 33010602011771号