题意:‘H’是山地,‘P’是平原,在平原上可以放置炮兵,攻击范围为图中黑色部分,炮兵不能放置在其他炮兵的攻击范围内,问最多能放多少个炮兵?
分析:用一个整数s表示一行的状态,s的第k位为1表示这一行第k列放置了炮兵。cnt[s] 表示 s的1的个数,即放置了炮兵的个数。
d[r][i][j]表示第 r 行状态为 i, r-1 行状态为 j 的最大炮兵数,d[r][i][j] = max( d[r-1][j][k] + cnt[i] ); 其中j k 与 i 不冲突。
每行最多有10个格子,状态为2^10,但有一些状态是非法的,合法状态在60个以内,所以要先预处理出所有合法状态。
const int N = 101, M = 15, K = 65; int n, m, ans; int d[N][K][K]; int s[K], cnt[K], p; int a[N]; char c[N][M]; void init(){ FOR(i,0,1<<m){ if(i&(i<<1) || i&(i<<2)) continue; s[p]=i; FOR(j,0,m) if(i&(1<<j)) cnt[p]++; p++; } } void read(){ cin>>n>>m; FOR(i,0,n) { cin>>c[i]; FOR(j,0,m) if(c[i][j]=='H') a[i]|=1<<j; } } void dp(){ FOR(k,0,p) { if(a[0]&s[k]) continue; d[0][k][0]=cnt[k]; checkmax(ans, d[0][k][0]); } FOR(i,1,n){ FOR(k,0,p){ if(a[i]&s[k])continue; FOR(u,0,p){ if(s[k]&s[u])continue; FOR(v,0,p){ if(s[v]&s[k])continue; checkmax(d[i][k][u], d[i-1][u][v] + cnt[k]); checkmax(ans, d[i][k][u]); } } } } cout<<ans<<endl; } int main(){ #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); #endif read(); init(); dp(); return 0; }