POJ 1185 炮兵阵地
题意:中文题……
解法:状压dp。用二进制数表示一行的状态,1表示放人,0表示不放人,考虑dp[i][j][k]表示第i行状态为j,第i-1行状态为k时的人数,则有状态转移方程当状态枚举状态jkl分别表示第i行、第i-1行、第i-2行状态,当jkl互相兼容时,dp[i][j][k] = max(dp[i][j][k], dp[i - 1][k][l] + num[j]),num[i]表示状态i中的人数,状态一共有210个,所以复杂度为n×210×210×210,是不可以接受的,但因为每行里人之间的距离至少为2,所以合法的状态只有60,可以深搜得到,这样复杂度变为n×60×60×60。状态i和j兼容的条件为i&j等于0,即没有两个士兵站在同一列上,可以按同样的方法压缩地图的状态。
代码:
#include<stdio.h> #include<iostream> #include<algorithm> #include<string> #include<string.h> #include<math.h> #include<limits.h> #include<time.h> #include<stdlib.h> #include<map> #include<queue> #include<set> #include<stack> #include<vector> #include<iomanip> #define LL long long #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1 | 1 using namespace std; char maze[110][15]; int state[100]; int tot = 0; int num[60]; void dfs(int now, int pos, int ni) { num[tot] = ni; state[tot++] = now; for(int i = pos + 3; i < 10; i++) { int tmp = 1 << i; dfs(now | tmp, i, ni + 1); } } int dp[105][60][60]; int M[105]; int main() { dfs(0, -3, 0); int n, m; while(~scanf("%d%d", &n, &m)) { memset(M, 0, sizeof M); for(int i = 1; i < n + 1; i++) { scanf("%s", maze[i]); for(int j = 0; j < 10; j++) { M[i] <<= 1; if(maze[i][j] != 'P') ++M[i]; } } memset(dp, 0, sizeof dp); for(int i = 1; i < n + 1; i++) { for(int j = 0; j < 60; j++) { for(int k = 0; k < 60; k++) { for(int l = 0; l < 60; l++) { if(state[l] & M[i]) continue; if(state[j] & state[k]) continue; if(state[j] & state[l]) continue; if(state[k] & state[l]) continue; dp[i][l][k] = max(dp[i][l][k], dp[i - 1][k][j] + num[l]); } } } } int ans = 0; for(int i = 0; i < 60; i++) for(int j = 0; j < 60; j++) ans = max(dp[n][i][j], ans); printf("%d\n", ans); } return 0; }