状压dp(B - 炮兵阵地 POJ - 1185 )
题目链接:https://cn.vjudge.net/contest/276236#problem/B
题目大意:略
具体思路:和我的上一篇写状压dp的思路差不多,不过就是这个题相当于上一个题的升级版,变成了左右,上下都会有限制,并且限制的步数是2,观察数据范围,如果按照上一个题的话,如果要是计算正确的范围取值的话,肯定会超时,所以我们可以先将所有的满足的情况先筛选出来,就算m取到10,总共的情况也就是60种,这样复杂度就大大的降下来了。
我们可以先预处理第一行和第二行,这样的话,我们就可以直接从第三行进行操作了,如果只是预处理第一行的话,第二行在往上走的时候,会取到第0行,而这一行我们是没有赋值的,所以我们应该预处理第一行和第二行。从第3行就可以直接进行操作了(就因为这个问题搞了一晚上。。。)。
我们开一个三维的dp数组,dp[i][j][k]。i代表的是第i行,j代表的是第i行取了哪种情况,k代表的是第i-1行的取值。
按道理来讲,我们应该一次比较三行的,可是为什么只是处理了两行?
因为我们在处理第i-1行的时候,我们比较的是dp[i-1][k][t]。这里的t是第i-2行,我们在处理第i行的时候就是按照一次比较三行来的,不过第三行的比较是通过第i-2行来进行比较的。
AC代码:
1 #include<iostream> 2 #include<cmath> 3 #include<stack> 4 #include<stdio.h> 5 #include<algorithm> 6 #include<queue> 7 using namespace std; 8 # define inf 0x3f3f3f3f 9 # define ll long long 10 const int maxn = 100+10; 11 char str[maxn]; 12 int a[maxn],ok[maxn],num[maxn]; 13 int dp[maxn][maxn][maxn]; 14 int cal(int t){ 15 int ans=0; 16 while(t){ 17 ans+=(t&1); 18 t>>=1; 19 } 20 return ans; 21 } 22 int main() 23 { 24 int n,m; 25 scanf("%d %d",&n,&m); 26 for(int i=1; i<=n; i++) 27 { 28 scanf("%s",str+1); 29 for(int j=1; j<=m; j++) 30 { 31 if(str[j]=='P') 32 a[i]=(a[i]<<1)+1; 33 else 34 a[i]=(a[i]<<1)+0; 35 } 36 } 37 int maxstate=(1<<m)-1; 38 int ans=0; 39 for(int i=0; i<=maxstate; i++) 40 { 41 if(((i<<1)&i)==0&&(((i>>1)&i)==0)&&(((i>>2)&i)==0)&&(((i>>2)&i)==0))//把合理的情况筛选出来。 42 { 43 ok[++ans]=i; 44 num[ans]=cal(i);//记录一下当前的合理情况的能放的炮弹个数记录下来。 45 } 46 } 47 int maxx=0; 48 for(int i=1;i<=ans;i++){ 49 if(((ok[i]&a[1])==ok[i])) 50 dp[1][i][0]=num[i]; 51 maxx=max(maxx,dp[1][i][0]); 52 } 53 for(int i=1;i<=ans;i++){ 54 if((ok[i]&a[2])==ok[i]){ 55 for(int j=1;j<=ans;j++){ 56 if(((ok[j]&ok[i])==0)&&((ok[j]&a[1])==ok[j])){ 57 dp[2][i][j]=max(dp[2][i][j],dp[1][j][0]+num[i]); 58 maxx=max(maxx,dp[2][i][j]); 59 } 60 } 61 } 62 } 63 for(int i=3;i<=n;i++){ 64 for(int j=1;j<=ans;j++){ 65 if((ok[j]&a[i])==ok[j]){ 66 for(int k=1;k<=ans;k++){ 67 if(((ok[j]&ok[k])==0)&&((ok[k]&a[i-1])==ok[k])){ 68 for(int l=1;l<=ans;l++){ 69 if(((ok[l]&ok[k])==0)&&((ok[l]&ok[j])==0)&&((ok[l]&a[i-2])==ok[l])){//在枚举第i-2行的时候,还需要和第i行和第i-1行进行比较。 70 dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][l]+num[j]); 71 maxx=max(maxx,dp[i][j][k]); 72 } 73 } 74 } 75 } 76 } 77 } 78 } 79 printf("%d\n",maxx); 80 return 0; 81 82 } 83