1. 程式人生 > >[NOI2001] 炮兵陣地 (狀壓Dp經典例題)

[NOI2001] 炮兵陣地 (狀壓Dp經典例題)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<cstring>
 6 using namespace std;
 7 const int MAXN=105;
 8 
 9 int Map[MAXN], Plan[MAXN], Num[MAXN], dp[MAXN][MAXN][MAXN];
10 int N, m, cnt=0, ans;
11 
12 inline int get_one(int
i){ 13 int sum=0; 14 for (int x=i; x; x-=x & (-x)) sum++; 15 return sum; 16 } 17 18 int main(){ 19 scanf("%d%d", &N, &m); 20 for (int i=1; i<=N; i++){ 21 char st[15]; 22 scanf("%s", st+1); 23 int len=strlen(st+1); 24 for (int j=1; j<=len; j++)
25 if (st[j]=='H') Map[i]+=(1<<j-1); 26 } //記錄當前行的地形 27 for (int i=0; i<(1<<m); i++){ 28 if ((!((i<<1)&i)) && (!((i>>1)&i)) && (!((i<<2)&i)) && (!((i>>2)&i))){ 29 cnt++; 30 Plan[cnt]=i;
31 Num[cnt]=get_one(i); //預處理當前行有幾個炮兵 32 if (!(Map[1] & Plan[cnt])) dp[1][cnt][0]=Num[cnt]; //預處理第一行的狀態 33 } 34 } 35 for (int i=1; i<=cnt; i++) 36 for (int j=1; j<=cnt; j++) 37 if ((!(Plan[i] & Plan[j])) && (!(Plan[j] & Map[2]))) 38 dp[2][j][i]=max(dp[1][i][0]+Num[j], dp[2][j][i]); 39 //預處理第二行的狀態 40 for (int i=3; i<=N; i++){ 41 for (int j=1; j<=cnt; j++) 42 if (!(Plan[j] & Map[i])){ 43 for (int k=1; k<=cnt; k++) 44 if (!(Plan[j] & Plan[k])){ 45 for (int q=1; q<=cnt; q++) 46 if (!(Plan[j] & Plan[q]) && !(Plan[q] & Plan[k])) 47 dp[i][j][k]=max(dp[i][j][k], dp[i-1][k][q]+Num[j]); 48 } 49 } 50 } 51 //Dp轉移 52 for (int i=1; i<=cnt; i++) 53 for (int j=1; j<=cnt; j++) 54 ans=max(ans, dp[N][i][j]); 55 //求最後一行的最值 56 printf("%d\n", ans); 57 return 0; 58 }