交一次就A了,自己都不敢相信。。。但愿不是水过去的。。。
这题跟炮兵阵地几乎一样,不同的是炮兵的炮能越过山,可是这里的杨桃打不穿障碍。一个处理的办法就是把当前的状态移一下之后与上障碍状态的反。
例如判断k状态向左打两格会不会打到自己,if(k&(((k<<1)&(~r[i]))<<1)) return false;这样就可以了。还要这题还比炮兵阵地的多了两个放向,但这样也只是多两句代码而已。。。
不熟悉状压DP的建议先做一下炮兵阵地这题
代码如下
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> using namespace std; int dp[2][200][200],s[3][1009],r[1009],cnt[3],num[1<<12],n,m; int num1(int x) //判断状态x里有几个1 { int ans=0; while(x>0) { x&=(x-1); ans++; } return ans; } bool can(int k,int i) { if(k&r[i]) return false; //判断有没有放在障碍上 if(k&(k<<1)) return false; //判断向左打一格会不会伤到同一行的自己 if(k&(((k<<1)&(~r[i]))<<1)) return false; //判断向左打两格会不会商到同一行的自己,模拟子弹,向左打一格之后与上障碍的非,表示遇到障碍后子弹消失了 return true; } bool can1(int j,int k) //判断本行的状态j会不会打到上一行的状态k { if(j&k) return false; if((j<<1)&k) return false; if((j>>1)&k) return false; return true; } bool can2(int j,int k,int r) //判断本行的状态j会不会打到上两行的状态k,r表示上一行的障碍的状态 { if(k&(j&(~r))) return false; if(k&(((j<<1)&(~r))<<1)) return false; if(k&(((j>>1)&(~r))>>1)) return false; return true; } int print(int k,int m=m) //这个函数调试用的。。。 { if(m<=0) return 2; print(k>>1,m-1); cout<<(k&1); if(m==::m) cout<<" "; return 2; } void DP() { int i=0,j,k,k1,k2; cnt[0]=0; for(j=0;j<(1<<m);j++) if(can(j,0)) s[0][cnt[0]++]=j; memset(dp,-1,sizeof(dp)); for(j=0;j<cnt[0];j++) { dp[0][j][0]=num[s[0][j]]; //print(s[0][j]);cout<<i<<" "<<dp[0][j][0]<<endl; } //cout<<endl; for(i=1;i<n;i++) { cnt[i%3]=0; for(j=0;j<(1<<m);j++) if(can(j,i)) s[i%3][cnt[i%3]++]=j; for(j=0;j<cnt[i%3];j++) { for(k1=0;k1<cnt[(i-1)%3];k1++) if(can1(s[i%3][j],s[(i-1)%3][k1])) { if(i>1) { for(k2=0;k2<cnt[(i-2)%3];k2++) if(can2(s[i%3][j],s[(i-2)%3][k2],r[i-1])) { if(dp[(i-1)&1][k1][k2]>=0) dp[i&1][j][k1]=max(dp[i&1][j][k1],dp[(i-1)&1][k1][k2]+num[s[i%3][j]]); //print(s[i%3][j]);print(s[(i-1)%3][k1]);print(s[(i-2)%3][k2]);cout<<i<<" "<<dp[i&1][j][k1]<<endl; } } else if(dp[(i-1)&1][k1][0]>=0) dp[i&1][j][k1]=max(dp[i&1][j][k1],dp[(i-1)&1][k1][0]+num[s[i%3][j]]); } } //cout<<endl; } } int main() { //freopen("in.txt","r",stdin); ios::sync_with_stdio(false); for(int i=0;i<(1<<12);i++) num[i]=num1(i); while(cin>>n>>m) { if(n==0 && m==0) return 0; int i,j,k; char c; for(i=0;i<n;i++) { r[i]=0; for(j=0;j<m;j++) { cin>>c; r[i]<<=1; if(c==‘X‘) r[i]|=1; } } DP(); int ans=0; i=n-1; for(j=0;j<cnt[i%3];j++) for(k=0;k<cnt[(i-1)%3];k++) ans=max(ans,dp[i&1][j][k]); cout<<ans<<endl; } return 0; }
别人写的另一个题解:
http://blog.csdn.net/just_water/article/details/9832761
原文:http://blog.csdn.net/w750636248/article/details/20000533