Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 19226 | Accepted: 7424 |
Description
如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。
现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。
Input
接下来的N行,每一行含有连续的M个字符('P'或者'H'),中间没有空格。按顺序表示地图中每一行的数据。N <= 100;M <= 10。
Output
Sample Input
5 4 PHPP PPHH PPPP PHPP PHHP
Sample Output
6
解题思路:每一行只跟上一行和上上一行有关系,而M<=10,因此每一行的状态不多,用程序枚举一下只有60种。所以,我们先预处理这60种状态,0表示未放,1表示已放。每一行用二进制表示,P用0表示可以放但是还没被放,H用1表示不可以放。
dp[k][sta1][sta2]表示当考虑第k行时,k-1行的是第sta1中状态,k-2行是第sta2中状态,之后所能放的最大值。
我们枚举在第k行的状态,当((way[sta1]|way[sta2]|mp[k])&way[i]) <= 0 时way[i]可以作为第k行的状态,way是预处理的60种状态,mp为读入的状态。
例如:设k-1行为01101,k-2行为01001,mp[k]为01010
01101
或
01001
-----
01101
表示第1、4位可以放,第2、3、5位不可以放,然后再跟mp[k]取或,mp[k]中0表示P,1表示H
01101
或
01010
-----
01111
则表示只有第1位可以放,然后再和way[i]取与,way[i]中的1表示第k行在该位放,0表示不放。
如果该位可以放而且第k行在该位放了,则0&1 == 0,
如果该位可以放而且第k行在该位不放,则0&0 == 0,
如果该位不可以放而第k行在该位放了,则1&1 == 1,
如果该位不可以放而第k行在该位不放,则1&0 == 0.
因此结果<=0表示第k行可以采用way[i]这个状态。
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
const int maxn = 105;
int dp[maxn][maxn][maxn] , v[maxn][maxn][maxn] , vv;
int way[maxn] , sum[maxn];
int mp[maxn] , N , M;
int cnt;
int vis[11];
void init(){
for(int i = 0; i < maxn; i++){
for(int j = 0; j < maxn; j++){
for(int k = 0; k < maxn; k++) dp[i][j][k] = 0 , v[i][j][k] = 0;
}
}
vv = 1;
}
void initial(){
memset(way , 0 , sizeof way);
memset(sum , 0 , sizeof sum);
memset(mp , 0 , sizeof mp);
memset(vis , 0 , sizeof vis);
cnt = 0;
}
void readcase(){
string str;
for(int i = 0; i < N; i++){
cin >> str;
int sta = 0;
for(int j = M-1; j >= 0; j--){
if(str[j] == 'H'){
sta += (1<<j);
}
}
mp[i] = sta;
}
}
void dfs(int i , int sta , int s){
if(i >= M){
way[cnt] = sta;
sum[cnt++] = s;
}else{
int flag = 1;
for(int k = 1; k <= 2; k++){
if(i-k >= 0 && vis[i-k] != 0){
flag = 0;
break;
}
}
dfs(i+1 , sta , s);
if(flag){
vis[i] = 1;
dfs(i+1 , sta+(1<<i) , s+1);
vis[i] = 0;
}
}
}
int DP(int k , int sta1 , int sta2){
if(k >= N) return 0;
if(v[k][sta1][sta2] == vv) return dp[k][sta1][sta2];
int ans = 0;
v[k][sta1][sta2] = vv;
for(int i = 0; i < cnt; i++){
if(((way[sta1]|way[sta2]|mp[k])&way[i]) <= 0){
ans = max(ans , DP(k+1 , i , sta1)+sum[i]);
}
}
return dp[k][sta1][sta2] = ans;
}
void computing(){
dfs(0 , 0 , 0);
printf("%d\n" , DP(0 , 0 , 0));
vv++;
}
int main(){
init();
while(~scanf("%d%d" , &N , &M)){
initial();
readcase();
computing();
}
return 0;
}