1. 程式人生 > 實用技巧 >POJ1185 炮兵陣地(狀態壓縮dp)

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; }