【题意】
给定一张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 }