Solution [NOI2001] artillery
Subject to the effect: in \ (\ n) line \ (m \) on the map are without conflict with the terrain in the artillery, and put as many artillery without conflicting requirements between artillery put up. how many artillery
This problem seen \ (m \) a very small range, and particularly attack range artillery, can determine a shape substantially pressure \ (DP \) . We artillery as \ (1 \) , then can be used a binary number to represent this line of artillery placed the state. But this question is like pressing \ (dp \) there are some differences. Like usual press \ (dp \) generally only need to consider the impact on the current line on the line, but this question compare special (toxic) special (tumor) , artillery will not only affect the line, but also affect the upper row , and therefore only consider the status of the current row will be \ (dp \) is not enough, we have to consider the state line
After the clear meaning of the questions, the state is not hard to define. We \ (f [i] [j ] [k] \) to represent the former \ (i \) line, the \ (i \) status line as \ (J \) , the first \ (i - 1 \) status line is \ (k \) when the number of artillery can be placed up to the state defined, then how to move it.?
Difficult to think \ (f [i] [j ] [k] = max \ {f [i - 1] [k] [z] \} \)
The last question, the boundary conditions?
\ (F [1] [X] [0] = CNT (X) \) , \ (CNT (X) \) represents a binary statistics \ (X \) in \ (1 \) number
Relatively easy to think of the equation, then the program how to achieve it?
- How to determine whether the artillery and terrain conflict?
The title of the mountain (that is, can not be placed artillery place) with \ (1 \) to represent, so that you can use a binary number to represent the state of the terrain of each line. Then take the terrain artillery state and put the state line to make a \ (and \) (bitwise aND) operation. If \ (and \) result is \ (0 \) , then it does not conflict with the description artillery terrain - How to determine whether a conflict with each other artillery?
To determine whether two lines of artillery conflict, they only need to do a \ (and \) operation can be. Ibid, if the result is \ (0 \) , then it does not explain artillery conflicting - Pretreatment
In order to accelerate the speed of the program, we can first pre-out possible states (such as if the next two artillery, then in accordance with the meaning of the questions is not enough). For a binary number represents the artillery placed \ (the X-\) , we You can \ (x \) and \ (the X-<< 2 \) , \ (the X-<< 1 \) , \ (the X->> 1 \) , \ (the X->> 2 \) are doing a \ (and \ ) operation, if the results are \ (0 \) to illustrate this program legal - Space consumption
we found that if directly open an array, the space occupied by approximately \ (100 \ times 1024 \ times 1024 = 104857600 \) a \ (int \) , space-consuming about \ (400MB \) . But the topic space constraints \ ( 128MB \) , the space will be fried, but take a look at our state transition equation, we find: calculation \ (i \) line will only use the first \ (i - \ 1) status line, so we can use scroll array to significantly optimize the space overhead
space occupied optimized: \ (2 \ Times 1024 \ 1024 Times = 2097152 \) a \ (int \) , about \ (8MB \) . more than enough
Meng presented the new code: when the program sprouting new implementation, not directly with the state, but the state's number
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 128;
const int maxm = 12;
const int maxs = 1 << maxm;//最多有多少个状态的状态数
int status[maxs],f[2][maxs][maxs],can[maxn],tot,n,m,full;//status表示状态,f为dp数组,can为地形,tot为状态总数(计数器),n,m由题意可知,full为全集
char str[maxm];//字符串临时数组
inline int cnt(int x){//统计二进制下数x里面1的数量
int ret = 0;
while(x){
if(x & 1)ret++;
x >>= 1;
}
return ret;
}
inline int check(int a,int b){
return a & b;
}
inline int check(int a,int b,int c){//a,b,c为三行炮兵摆放的状态,判断是否可行
return check(a,b) | check(a,c) | check(b,c);
}
int main(){
#ifdef LOCAL
freopen("fafa.in","r",stdin);//本机调试用
#endif
scanf("%d %d",&n,&m);
for(int i = 1;i <= n;i++){//读入地形
scanf("%s",str + 1);
for(int j = 1;j <= m;j++)
if(str[j] == 'H')can[i] = (can[i] << 1) | 1;
else can[i] = can[i] << 1;
}
full = (1 << m) - 1;//全集
for(int i = 0;i <= full;i++)//预处理状态
if((!(i & (i << 2))) && (!(i & (i << 1))) && (!(i & (i >> 1))) && (!(i & (i >> 2))))
status[++tot] = i;//如果状态i可行,把它丢进status数组
for(int i = 1;i <= tot;i++)
f[1 % 2][i][1] = cnt(status[i]); //边界条件,1号状态表示没有炮兵(由初始化代码可以看出来)
for(int i = 2;i <= n;i++)
for(int j = 1;j <= tot;j++)
if(!(status[j] & can[i]))//不和地形冲突
for(int k = 1;k <= tot;k++)
if((!(status[k] & can[i - 1])) && (!check(status[j],status[k])))//不和地形冲突,且炮兵不互相冲突
for(int z = 1;z <= tot;z++)
if((!(status[z] & can[i - 2])) && (!check(status[j],status[k],status[z])))//同上
f[i % 2][j][k] = max(f[i % 2][j][k],f[(i - 1) % 2][k][z] + cnt(status[j]));//滚动数组,进行状态转移
int ans = 0;
for(int i = 1;i <= tot;i++)//统计答案
for(int j = 1;j <= tot;j++)
ans = max(ans,f[n % 2][i][j]);
printf("%d\n",ans);
return 0;
}