//208K 375MS C++
#include <cstdio>
#include <cstring>
using namespace std;
long long maxNum;
int W;
int H;
#define NN (101)
#define S (1<<9 + 1)
int degree[13] = {0, 1, 2, 4 ,8,
16, 32, 64, 128,
256, 512, 1024, 2048};
// int DP[NN][S][S];
int DP[65][65];
int temp[65][65];
int rowNumber[NN];
char mapRow[11];
int OneNum[S];
int validNum;
int valid[S];
//状态s[x]下有多少个1
int getsum(int x)
{
int num=0;
while(x>0)
{
if(x&1)num++;
x>>=1;
}
return num;
}
//状态s[x]是否造成行冲突
bool ok(int x)
{
if(x&(x<<1))return false;
if(x&(x<<2))return false;
return true;
}
void find() {
validNum = 0;
memset(valid, 0, sizeof(valid));
for(int i = 0; i < (1<<W); i++) //i枚举所有m位的二进制数
{
if(ok(i)) {
valid[validNum] = i;
OneNum[validNum++] = getsum(i);
}
}
}
void beginDP() {
for (int i = 0; i < validNum; i++) {
if (!((~rowNumber[1]) & valid[i])) {
DP[i][0] = OneNum[i];
}
}
for (int row = 2; row <= H; row++) {
for (int i = 0; i < validNum; i++) {
if ((~rowNumber[row]) & valid[i]) {
continue;
}
for (int i1 = 0; i1 < validNum; i1++) {
if ((valid[i] & valid[i1])) {
continue;
}
if (row == 2 &&
!((~rowNumber[row-1]) & valid[i1]) &&
(valid[i] & valid[i1]) == 0) {
temp[i][i1] = OneNum[i] + OneNum[i1];
} else if ((valid[i] & valid[i1]) == 0) {
int max = -1;
for (int k = 0; k < validNum; k++) {
if ((valid[i] & valid[k])) {
continue;
}
if ((valid[i1] & valid[k])) {
continue;
}
if (DP[i1][k] == -1) {
continue;
}
int curNum = DP[i1][k] + OneNum[i];
max = max > curNum ? max : curNum;
}
temp[i][i1] = max;
}
}
}
memcpy(DP, temp, sizeof(DP));
}
maxNum = 0;
for (int i = 0; i < validNum; i++) {
for (int j = 0; j < validNum; j++) {
maxNum = maxNum > DP[i][j] ? maxNum: DP[i][j];
}
}
}
void getSolutionNum() {
find();
beginDP();
printf("%lld\n", maxNum);
}
int main() {
while( scanf("%d %d", &H, &W) != EOF) {
memset(DP, -1, sizeof(DP));
memset(rowNumber, 0, sizeof(rowNumber));
memset(temp, -1, sizeof(temp));
for (int y = 1; y <= H; y++) {
int x = 1;
scanf("%s", mapRow);
for (; x <= W; x++) {
rowNumber[y] += (mapRow[x-1] == 'P')*degree[x];
}
}
getSolutionNum();
}
}
应该算是DP的经典中高阶题了, 妈的,把我做成跪斗士了,尤其最后的几次TLE简直令人无语。。。
做这道题之前, 刚把3254做了,心想着趁着余温把这道也给干了,谁料最后也是被反干。
一开始,还以为是3254的简单变形,只不过影响范围从一行变成了两行,不过自己也知道不会这么简单,果然原来的思路是不行的,
后来查了下,才醒悟可以将DP数组的维度扩展,以前的DP[i][j]表示 第i行的状态是 j时的最大炮兵数量,现在把DP数组扩一个维度,
DP[i][j][k]表示第i行状态是j, 第i-1行状态是k时,能部署的最大炮兵数.
那么对于DP[i][j][k]来说,其递推公式就是:
DP[i][j][k] = max(DP[i-1][k][s](s代表 i - 2行的所有可能取值) + oneNum[i]);
后面因为DP数组太大,MLE了,不得不搞了滚动数组(搞了一个temp数组来做临时数组,每一行处理完以后,再将temp数组copy到DP)。
然后又TLE了,发现是因为我在DP遍历某一行的状态i时,直接是从0 到 1<<L - 1, 其实里面有很多状态完全可以连for循环都不进,
因此可以在之前,先把所有不满足 (i&(i<<1)) 和 (i&(i<<2)) 的状态i全部拿掉,然后专门搞一个数组vaild保存满足的状态,这样,在DP的时候,只遍历valid数组即可,
改完还是TLE,跪了多次,找不到原因,后来发现自己的DP数组开的太大,改成了某个解答中的65, 立刻AC了。
无语了.. memcpy()拷贝不同尺寸数组竟然费时相差那么大? 以后要专门试一试.
先把简略报告放这里,以后还要写篇详细的.