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 }
View Code

相关文章: