炮兵阵地

poj1185:http://poj.org/problem?id=1185

题意:这道题太经典了,看到题目就知道题意,故题意略。

题解:经典的状压dp。以前觉得dp是个很难的东西,做了这一题之后发现,dp其实根本不难,真的,而且很好打。

思维过程:拿到题之后,由于之前做过,所以知道是状压dp。接着想怎么解决。普通的dp,不要考虑障碍,这一题中有障碍限制。多以第一步要处理这个障碍。想到了用这样的方式来解决。把出现h的地方标记为1,其余记0,从右到左,从低位到高位,求出这个数,然后枚举状态的时候,只要把枚举的状态,和这个数&,如果出现1则是不满足的,说明有炮兵出现在H上。好了,障碍解决了。接下来可以dp。一开始想到的是用二维的,发现打出的结果不对,检查一一下,貌似转移不太对。于是,就考虑三维的了。一下子豁然开朗,思路很清晰了。打完之后,过了样例,接着交了,结果wa。不知道错在哪里,就看了discuss。其实这是不对的,应该自己思考。其实,这时候,如果找不出来错误,应该具几组特例的。会发现 11 p,就不对,然后就知道错在哪里,一开始我是第一行初始化dp[i][0],但是最后的结果却是从1开始枚举,所以如果样例只有1,2行的话,答案就不对了。于是,改改,交了,就过了。这里还有一个问题,就是,dp[][i][j],记录的是第i个状态,不是i所代表的状态,真正的状态是s[i],这样就节省了很多空间,这样开3维的才有可能。接下来,是我的代码。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 int n,m;
 7 char mp[102][12];
 8 int state[102];
 9 int ct[1003],num,s[1003];
10 int dp[102][67][67];
11 bool isok(int x){
12   if((x&(x<<1))||(x&(x<<2)))return false;
13   return true;
14 }
15 void solve1(){
16   for(int i=1;i<=n;i++){
17         int counts=1,ans=0;
18     for(int j=m;j>=1;j--){
19         if(mp[i][j]=='H')
20           ans+=counts;
21          counts*=2;
22     }
23     state[i]=ans;
24   }
25 }
26 int counts(int x){
27     int ans=0;
28     while(x){
29         ans+=(x&1);
30         x/=2;
31     }
32   return ans;
33 }
34 void solve2(){
35   num=0;
36   for(int i=0;i<(1<<m);i++){
37     if(isok(i)){
38         num++;
39         s[num]=i;
40         ct[num]=counts(i);
41     }
42   }
43 }
44 int main(){
45   while(~scanf("%d%d",&n,&m)){
46        memset(mp,0,sizeof(mp));
47        memset(dp,0,sizeof(dp));
48        memset(ct,0,sizeof(ct));
49        memset(s,0,sizeof(s));
50        memset(state,0,sizeof(state));
51        for(int i=1;i<=n;i++)
52           for(int j=1;j<=m;j++)
53            cin>>mp[i][j];
54        solve1();
55        solve2();
56        for(int i=1;i<=num;i++){
57         if(s[i]&state[1])continue;
58         dp[1][i][0]=ct[i];
59        }
60        for(int i=1;i<=num;i++){
61           for(int j=1;j<=num;j++){
62             if(s[i]&s[j])continue;
63             if(state[2]&s[i])continue;
64             if(state[1]&s[j])continue;
65             dp[2][i][j]=max(dp[2][i][j],dp[1][j][0]+ct[i]);
66           }
67        }
68        for(int i=3;i<=n;i++){
69           for(int j=1;j<=num;j++){
70              if(s[j]&state[i])continue;
71             for(int k=1;k<=num;k++){
72                  if(s[k]&s[j])continue;
73                   if(s[k]&state[i-1])continue;
74                  for(int g=1;g<=num;g++){
75                     if(s[k]&s[g])continue;
76                     if(s[j]&s[g])continue;
77                     if(s[g]&state[i-2])continue;
78                     dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][g]+ct[j]);
79                 }
80             }
81           }
82        }
83      int ans=0;
84      for(int i=1;i<=num;i++){
85         for(int j=0;j<=num;j++)
86         ans=max(ans,dp[n][i][j]);
87      }
88      printf("%d
",ans);
89   }
90 }
View Code
原文地址:https://www.cnblogs.com/chujian123/p/3873758.html