本题过于经典......
对于这种网格状压DP,套路一波刷表法DFS转移就没了。
三进制状压,0表示当前,上一个都没有。1表示当前无,上一个有。2表示当前有。
转移的条件就是上一行为0,当前不是山地,且左边两个都不是2。
注意有个坑点,全部转移会超时。因为本题有很多废状态(山地),初始化-1然后判断是否转移即可。
1 #include2 #include 3 #include 4 5 const int N = 110, M = 12; 6 7 int n, m, f[N][200010], pre[M], now[M], ans, G[N][M]; 8 char str[M]; 9 10 inline int zip(int *a) { 11 int t = 0; 12 for(int i = 0; i < m; i++) { 13 t = t * 3 + a[i]; 14 } 15 return t; 16 } 17 18 inline void unzip(int x, int *a) { 19 for(int i = m - 1; i >= 0; i--) { 20 a[i] = x % 3; 21 x /= 3; 22 } 23 return; 24 } 25 26 void DFS(int x, int y, int lastans) { 27 if(y >= m) { 28 int s = zip(now); 29 f[x][s] = std::max(f[x][s], lastans); 30 ans = std::max(ans, lastans); 31 return; 32 } 33 DFS(x, y + 1, lastans); 34 if(!G[x][y] && pre[y] == 0 && (y < 1 || now[y - 1] < 2) && (y < 2 || now[y - 2] < 2)) { 35 now[y] = 2; 36 DFS(x, y + 1, lastans + 1); 37 now[y] = 0; 38 } 39 return; 40 } 41 42 int main() { 43 memset(f, -1, sizeof(f)); 44 scanf("%d%d", &n, &m); 45 for(int i = 1; i <= n; i++) { 46 scanf("%s", str); 47 for(int j = 0; j < m; j++) { 48 G[i][j] = (str[j] == 'H'); 49 } 50 } 51 52 int lm = 1; 53 for(int i = 1; i <= m; i++) { 54 lm *= 3; 55 } 56 f[0][0] = 0; 57 for(int i = 0; i < n; i++) { 58 for(int s = 0; s < lm; s++) { 59 if(f[i][s] == -1) { 60 continue; 61 } 62 unzip(s, pre); 63 for(int j = 0; j < m; j++) { 64 now[j] = std::max(0, pre[j] - 1); 65 } 66 DFS(i + 1, 0, f[i][s]); 67 } 68 } 69 70 printf("%d", ans); 71 return 0; 72 }
我数组一开始开了2^m个......应该是3^m。