POJ1185 炮兵阵地(状态压缩dp)
https://ac.nowcoder.com/acm/problem/16886
思路:m<=10,每行用0~1023数字的二进制数来表示状态,1表示能放,0表示不能放。同时他要满足不能放在途中H处,
那么把每行PHPH的字符串转换成0101串的状态,H记为1,p记为0,记录在statu。判断一个能不能根据这个状态放在地图上,
只要看他们&运算是不是0(不是0说明有棋子放在H上)。
因为炮兵能攻击到他正下方的2行,所以用dp记录他当前行状态以及上一行状态。
dp[i][j][k]表示在第i行中状态为j,第i-1行状态为k是的最大能放棋子数。
在第i行中,用now表示当前行状态,p表示上一行状态,lp表示上上行状态,num[x]表示状态x的棋子数。
dp方程:dp[i][now][p]=max(dp[i-1][p][lp]+num[now]) {lp取1~up},up表示合法状态上限。
每次都用&运算判断该行与上一行,与上上行是否合法。
代码:
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<sstream> #include<vector> #include<stack> #include<deque> #include<cmath> #include<map> #include<queue> #include<bitset> //#include<hash_map> #define sd(x) scanf("%d",&x) #define lsd(x) scanf("%lld",&x) #define ms(x,y) memset(x,y,sizeof x) #define fu(i,a,b) for(int i=a;i<=b;i++) #define fd(i,a,b) for(int i=a;i>=b;i--) #define all(a) a.begin(),a.end() #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 using namespace std; //using namespace __gnu_cxx; typedef long long ll; typedef unsigned long long ull; typedef long double ld; const int maxn=1e3+79; const int mod=998244353; const ll INF=0x7f7f7f7f; const double pi=acos(-1); ll dp[10][1030][1030]; //第i行,第i-1行状态,第i-2行状态 int num[1030],statu[1030],n,m; bool check(int x,int statu) { //按地图看该状态能不能放 if((x&statu)!=0) return 0; //检查x状态是否合法 if((x&(x>>1))!=0 || (x&(x>>2))!=0) return 0; return 1; } int main() { sd(n);sd(m); fu(i,1,n) { //把PHPH的字符串转换成0101串的状态,H记为1,p记为0,记录在statu string s;cin>>s; int x=1;//记录处于第几位 fd(j,s.size()-1,0) { if(s[j]=='H') statu[i]+=x; x<<=1;//x左移一位 } } int up=(1<<m)-1;//合法状态上限 fu(i,1,up) { num[i]=num[i>>1]+(i&1);//状态为i的棋子数 } //特判n=1的情况 if(n==1) { int ans=0; fu(i,0,up) { if(!check(i,statu[1])) continue; ans=max(ans,num[i]); } printf("%d\n",ans); return 0; } //初始化 fu(now,0,up) { if(!check(now,statu[2])) continue; fu(p,0,up) { if(!check(p,statu[1])||(now&p)!=0) continue; dp[0][now][p]=num[now]+num[p]; } } fu(i,3,n) { fu(now,0,up)//当前状态 { if(!check(now,statu[i])) continue; fu(p,0,up)//上一行状态 { if(!check(p,statu[i-1])||(now&p)!=0) continue; fu(lp,0,up)//上上行状态 { if(!check(lp,statu[i-2])||(p&lp)!=0||(now&lp)!=0) continue; dp[i&1][now][p]=max(dp[i&1][now][p],dp[(i-1)&1][p][lp]+num[now]); } } } } ll ans=0; fu(now,0,up) fu(p,0,up) { if((now&p)==0)//判断是否合法 ans=max(ans,dp[n&1][now][p]); } printf("%lld\n",ans); return 0; }
浙公网安备 33010602011771号