1. 程式人生 > >【NOI2001】炮兵陣地

【NOI2001】炮兵陣地

turn define ret pla ont isp cnblogs 一行 include

【題意】

  給定一張n*m的圖,每個位置要麽是P,要麽是H。P的位置可以放炮兵,H則不行。炮兵會朝四個方向,距離2個單位的方格進行攻擊,求在沒有炮兵互傷的情況下,最多能放的炮兵數量。

【題解】

  這道題死坑。

  一開始知道是狀壓dp。但是狀態想的比較麻煩,寫了半天沒寫出來。

  看了網上其它神犇的題解,發現狀態很簡單:DP[I][J][K],表示當前為第I行,第I行狀態為J,第I-1狀態為K,狀態轉移方程比較好想的。

  不過每一行無腦算狀態有最多大概1000種,狀態顯然存不下。考慮一下題目的限制,估算一下每一行的合法狀態不超過100個吧。於是先預處理出合法狀態,再標一下號就行了。

  其實難點還是在狀態的構造吧(可能我比較腦殘)。

  時間復雜度O(n*k^3),k表示狀態數。

【代碼】

技術分享
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #define N 105
 5 using namespace std;
 6 pair <int,int> p[N][N];
 7 int n,m,ans,dp[N][N][N],x,y,z,len[N];
 8 char a[N][N];
 9 void dfs(int i,int t,int s,int k)
10 {
11     if (t==m)
12 { 13 p[i][++len[i]]=make_pair(s,k); 14 return; 15 } 16 dfs(i,t+1,s<<1,k); 17 if (a[i][t+1]==P && (s&3)==0) dfs(i,t+1,(s<<1)+1,k+1); 18 } 19 int main() 20 { 21 cin>>n>>m; 22 for (int i=1;i<=n;++i) 23 { 24 cin>>a[i]+1
; dfs(i,0,0,0); 25 } 26 len[0]=1; 27 for (int i=1;i<=len[1];++i) 28 dp[1][1][i]=p[1][i].second; 29 ans=0; 30 for (int i=2;i<=n;++i) 31 for (int j=1;j<=len[i-2];++j) 32 for (int k=1;k<=len[i-1];++k) 33 { 34 x=p[i-2][j].first; 35 y=p[i-1][k].first; 36 if ((x&y)) continue; 37 for (int o=1;o<=len[i];++o) 38 { 39 z=p[i][o].first; 40 if ((x&z)||(y&z)) continue; 41 dp[i][k][o]=max(dp[i][k][o],dp[i-1][j][k]+p[i][o].second); 42 if (i==n) ans=max(ans,dp[i][k][o]); 43 } 44 } 45 cout<<ans<<endl; 46 return 0; 47 }
View Code

【NOI2001】炮兵陣地