P2704 [NOI2001]炮兵阵地 状态压缩DP 位运算 滚动数组 ~

如果你不知道以下内容,本文会更好理解或者你根本不需要这篇文章:
位运算、二进制、动态规划等
你可以在这里学习:状压 DP - OI:Wiki https://oi-wiki.org/dp/state/

好久不记录,这次记一下吧!

基本上就是模板题,一开始写的代码当中虽然考虑到了当前行不能和前两行互相攻击,却一不小心致使前一行可能被其上上行攻击。

总之最后的核心公式酱紫——

f [ l i n e ] [ 第   l i n e   行 摆 放 的 状 态 ] [ 第   l i n e − 1   行 摆 放 的 状 态 ] f\left [ line\right ]\left [ 第\ line\ 行摆放的状态\right ]\left [ 第\ line-1\ 行摆放的状态\right ] f[line][ line ][ line1 ]

注:用滚动数组,一开始没用滚动数组直接莽了个

f [ 100 + 10 ] [ ( 1 < < 10 ) + 10 ] [ ( 1 < < 10 ) + 10 ] f[100+10][(1<<10)+10][(1<<10)+10] f[100+10][(1<<10)+10][(1<<10)+10]

结果出大问题,MLE、MLE、MLE……

然后发现永远只要用前一行的数据,于是就滚起来惹……

#include
using namespace std;
int n,m,cnt1[1024],f[5][2000][1000];
string input;
vector<int> states[100+1];
bool b[1024];
void dfs(int line,int i,int st,int cnt); //这个 DFS 是用来预处理每一行可以摆放的所有情况,例如 PHHH 就只有一种情况,因为它只有第一个能摆,当然这里枚举的时候已经排除了横向上有可以互相攻击的炮兵之可能情况
bool cmp(int s1,int s2); //用来比较两行能不能互相攻击……好像有点脱裤子放P
void rolldown(int line); //这个函数是我用来滚动数组时,给表示当前行数据的数组赋零的
int main()
{    
    cin>>n>>m;
    for(int i=1;i<=n;i++) 
    {
        cin>>input;
        memset(b,0,sizeof(b)); 
        if(input[0]=='P') for(auto j:{0,1}) dfs(i,0,j,j);   
        else dfs(i,0,0,0);
    }
    if(n==1) //俺这单独处理了
    {
        int ans=-1;
        for(auto i:states[1]) ans=max(ans,cnt1[i]);
        cout<<ans<<'\n';
        return 0;
    }
    for(auto i:states[2]) for(auto j:states[1]) if(cmp(i,j)) f[2][i][j]=cnt1[i]+cnt1[j]; //处理第二行
    int A=3,B=2;
    for(int i=3;i<=n;i++)
    {  
        for(auto t:states[i]) for(auto s:states[i-1]) for(auto o:states[i-2]) //分别枚举这行、上行、上上行的所有情况 
        	if(cmp(t,s)&&cmp(t,o)&&cmp(o,s)) //判断一下这三行互相干扰否 
        		f[A][t][s]=max(f[A][t][s],cnt1[t]+f[B][s][o]);  
        swap(A,B); //滚动数组,反正就是两行数组循环用
        rolldown(A);
    }
    int ans=-1; 
    for(auto i:states[n]) for(auto j:states[n-1]) ans=max(ans,f[B][i][j]);
    cout<<ans<<'\n';
    return 0;
}  
void dfs(int line,int i,int st,int cnt) {
    if(i==m-1)
    {
        if(!b[st]) 
        {
            b[st]=1;  
            states[line].push_back(st);
            cnt1[st]=cnt;
        } 
        return;
    }
    if(input[i+1]=='H') dfs(line,i+1,st<<1,cnt); 
    else if(input[i+1]=='P')
    {
        dfs(line,i+1,st<<1,cnt);
        if((st&1)||((st>>1)&1))return; 
        dfs(line,i+1,(st<<1)+1,cnt+1);
    }
}
bool cmp(int s1,int s2) {if(s1&s2) return false; return true;}
void rolldown(int line) {memcpy(f[line],f[4],sizeof(f[1]));} //f[4]始终是全零

总体上看,总觉这代码哪里蠢蠢的(逃

你可能感兴趣的:(算法题目题解&&RECORD)