Solution to a problem P2704 [[NOI2001] artillery]

Topic Link

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;
}

Guess you like

Origin www.cnblogs.com/colazcy/p/11514754.html