这道题是状态压缩DP。应该是很有用的方法。
这道题每行可能的状态(每个col放不放炮兵)可以表示为int,即int state。
,同样地形也可以表示为int,某位为1表示该处是hill,即int terrain[N]。
这样状态在某行是否合法可以通过terrain[row] & state判断。如果不为0,说明在hill放兵了,不合法。
这样,总状态数是2 << M,因为每处都可以放或不放兵。但是有些状态可以很轻松除去的,即如果i处放兵,那么无论地形如何,i - 1, i - 2, i + 1, i + 2处都不能放兵。这样需要考虑的状态就只有60种(我没有hard-code这个数字,而用的是vector)。
由于每一行的状态只依赖于前两行,所以处理完一行后,只需保存这行及前一行的状态,就可以接着处理后面的行。
DP其实和枚举差不多,就是对之前两行的所有状态(DP[row - 1][i][j])进行遍历,然后更新当前行的状态(DP[row][k][i]):
DP[row][k][i] = max(DP[row][k][i], DP[row - 1][i][j] + ones[k]);
thestoryofsnow | 1185 | Accepted | 1840K | 485MS | C++ |
/*
ID: thestor1
LANG: C++
TASK: poj1185
*/
#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <limits>
#include <string>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <cassert>
using namespace std;
bool hastroop(int state, int col)
{
return state & (1 << col);
}
bool isvalidcol(int col, int M)
{
return 0 <= col && col < M;
}
int nof1s(int state)
{
int cnt = 0;
while (state)
{
state &= state - 1;
cnt++;
}
return cnt;
}
int main()
{
int N, M;
scanf("%d%d", &N, &M);
// if terrain[row][col] is 1, then (row, col) is H (hill)
// P (plain) otherwise
std::vector<int> terrain(N, 0);
for (int row = 0; row < N; ++row)
{
for (int col = 0; col < M; ++col)
{
char t;
scanf(" %c", &t);
if (t == 'H')
{
terrain[row] |= 1 << col;
}
else
{
assert(t == 'P');
}
}
}
// printf("terrain:\n");
// for (int row = 0; row < N; ++row)
// {
// // terrain[row];
// for (int col = 0; col < M; ++col)
// {
// if (terrain[row] & (1 << col))
// {
// printf("H");
// }
// else
// {
// printf("P");
// }
// }
// printf("\n");
// }
int power = (int)pow((double)2, M);
std::vector<int> validstates, ones;
for (int state = 0; state < power; ++state)
{
bool isvalidstate = true;
for (int col = 0; col < M; ++col)
{
// column col has troop
if (hastroop(state, col))
{
// col - 1 also has troop
if (isvalidcol(col - 1, M) && hastroop(state, col - 1))
{
isvalidstate = false;
break;
}
// col - 2 also has troop
if (isvalidcol(col - 2, M) && hastroop(state, col - 2))
{
isvalidstate = false;
break;
}
// col + 1 also has troop
if (isvalidcol(col + 1, M) && hastroop(state, col + 1))
{
isvalidstate = false;
break;
}
// col + 2 also has troop
if (isvalidcol(col + 2, M) && hastroop(state, col + 2))
{
isvalidstate = false;
break;
}
}
}
if (isvalidstate)
{
validstates.push_back(state);
ones.push_back(nof1s(state));
}
}
int S = validstates.size();
std::vector<std::vector<std::vector<int> > > DP(N, std::vector<std::vector<int> > (S, std::vector<int> (S, 0)));
for (int row = 0; row < N; ++row)
{
for (int k = 0; k < S; ++k)
{
if (validstates[k] & terrain[row])
{
continue;
// for (int i = 0; i < S; ++i)
// {
// DP[row][k][i] = 0;
// }
}
else
{
for (int i = 0; i < S; ++i)
{
if (validstates[k] & validstates[i])
{
continue;
}
if (row == 0)
{
DP[row][k][i] = ones[k];
continue;
}
for (int j = 0; j < S; ++j)
{
if (validstates[k] & validstates[j])
{
continue;
}
DP[row][k][i] = max(DP[row][k][i], DP[row - 1][i][j] + ones[k]);
}
}
}
}
}
int K = 0;
for (int i = 0; i < S; ++i)
{
for (int j = 0; j < S; ++j)
{
K = max(K, DP[N - 1][i][j]);
}
}
printf("%d\n", K);
return 0;
}