洛谷P2704炮兵阵地-题解
原题:
思路:
状压DP经典题目
对于每一个点是否可以放部队
只要考虑前两行有没有部队
这一行有没有两个部队距离在两格之内
这个点是不是山
即可
状态转移方程:
dp[L][S][i]=max(dp[L][S][i],dp[FL][L][i-1]+Sum[S]);
搭配一些二进制处理
在输入地图的时候将H换成1,P换成0
然后S&a[i]如果结果不是0就说明有的放在了山丘上
同理用这个方法可以判断是否在前两行范围内
为了判断横向范围,我们可以将该状态分别右移1位和2位
然后取并
若结果不是0,就有在范围之内的。
代码:
#include <bits/stdc++.h> using namespace std; int n,m,dp[1<<10][1<<10][3],a[105],sum[1<<10]; int ans; int getsum(int S) { int tot=0; while(S) { if(S&1) tot++; S>>=1; } return tot; } int main() { ans=0; cin >> n >> m; for(int i=0;i<n;i++) for(int j=0;j<m;j++) { char x; cin >> x; a[i]<<=1; if(x=='H') a[i]+=1; } for(int i=0;i<(1<<m);i++) sum[i]=getsum(i); for(int S=0;S<(1<<m);S++) if(!(S&a[0] || (S&(S<<1)) || (S&(S<<2)))) dp[0][S][0]=sum[S]; for(int L=0;L<(1<<m);L++) for(int S=0;S<(1<<m);S++) if(!(L&S || L&a[0] || S&a[1] || (L&(L<<1)) || (L&(L<<2)) || (S&(S<<1)) || (S&(S<<2)))) dp[L][S][1]=sum[S]+sum[L]; for(int i=2;i<n;i++) for(int L=0;L<(1<<m);L++) { if(L&a[i-1]||(L&L<<1)||(L&L<<2)) continue; for(int S=0;S<(1<<m);S++) { if(S&a[i] || L&S || (S&(S<<1)) || (S&(S<<2))) continue; for(int FL=0;FL<(1<<m);FL++) { if(FL&L||FL&S||FL&a[i-2]||(FL&FL<<1)||(FL&FL<<2)) continue; dp[L][S][i%3]=max(dp[L][S][i%3],dp[FL][L][(i-1)%3]+sum[S]); } } } for(int L=0;L<(1<<m);L++) for(int S=0;S<(1<<m);S++) ans=max(ans,dp[L][S][(n-1)%3]); cout << ans << endl; return 0; }