POJ1185 炮兵部队问题:
在平原上才能放置炮兵,每个炮兵的上下左右2格之内都不能出现别的炮兵
可以考虑在当前行放置炮兵它的右侧和下侧绝对不会出现炮兵即可,左侧和上侧就能省去考虑
明显的状态压缩dp题,但是题目所给的有10列,因为每行都与前两行的状态有关,那么也就是根据当前,上一行,上上行3行状态来修改
dp[i][v][u]的状态方程
因为这里直接3重循环会爆,但是我们很容易发现,可以预处理一些关于行的合法状态,那么状态数就少了很多,接下来考虑的时候就省去了行上的相关影响
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 const int N = 1<<11; 7 int dp[105][100][100] , state[N]; 8 int can[100] , tot[100] , cnt; 9 char str[15]; 10 11 void init_dfs(int k , int u , int v) 12 { 13 if(k<0){ 14 tot[cnt] = v; 15 can[cnt++] = u; 16 return; 17 } 18 init_dfs(k-3 , u|(1<<k) , v+1); 19 init_dfs(k-1 , u , v); 20 } 21 22 int main() 23 { 24 // freopen("a.in" , "r" , stdin); 25 int n,m; 26 while(scanf("%d%d" , &n , &m) != EOF) 27 { 28 for(int i=1 ; i<=n ; i++){ 29 scanf("%s" , str); 30 state[i] = 0; 31 for(int j=0 ; j<(int)strlen(str) ; j++){ 32 state[i] <<= 1; 33 if(str[j] == 'P') state[i]+=1; 34 } 35 // cout<<"state: "<<state[i]<<endl; 36 } 37 //找到所有符合的状态,减少状态数 38 cnt = 0; 39 init_dfs(m-1 , 0 , 0); 40 // cout<<cnt<<endl; 41 42 if(n==1){ 43 int maxn=0; 44 for(int i=0 ; i<cnt ; i++) 45 if((state[1]&can[i]) == can[i]) 46 maxn = max(maxn , tot[i]); 47 printf("%d\n" , maxn); 48 continue; 49 } 50 51 memset(dp , 0 , sizeof(dp)); 52 for(int i=0 ; i<cnt ; i++){ 53 for(int j=0 ; j<cnt ; j++){ 54 int t1 = state[1]&can[i] , t2 = state[2]&can[j]; 55 if(t1 == can[i] && t2 == can[j] && !(can[i]&can[j])) 56 { 57 // cout<<"test: "<<i<<" "<<j<<" "<<can[i]<<" "<<can[j]<<" tot: "<<tot[i]<<" "<<tot[j]<<endl; 58 dp[2][i][j] = tot[i] + tot[j]; 59 } 60 } 61 } 62 state[0] = (1<<m)-1; 63 for(int i=3 ; i<=n ; i++){ 64 for(int u=0 ; u<cnt ; u++){ 65 if((state[i]&can[u]) < can[u]) continue; 66 for(int v=0 ; v<cnt ; v++){ 67 if((state[i-1]&can[v]) < can[v]) continue; 68 if((can[v]&can[u])) continue; 69 for(int w=0 ; w<cnt ; w++){ 70 if((state[i-2]&can[w]) < can[w]) continue; 71 if((can[v]&can[w]) || (can[u]&can[w])) continue; 72 dp[i][v][u] = max(dp[i][v][u] , dp[i-1][w][v] + tot[u]); 73 } 74 } 75 } 76 } 77 int maxn = 0; 78 for(int i=0 ; i<cnt ; i++){ 79 for(int j=0 ; j<cnt ; j++) 80 maxn = max(maxn , dp[n][i][j]); 81 } 82 printf("%d\n" , maxn); 83 } 84 return 0; 85 }