2019.9.1 炮兵阵地

Posted qxds

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019.9.1 炮兵阵地相关的知识,希望对你有一定的参考价值。

传送门

明显状压dp 用dp[i][j][k]记录前i行最后一行状态编号是j且倒数第二行状态编号是k最多能放几个

所以我们先初始化dp[1]和dp[2]

其中dp[1][j][0]=bj[1][j] 因为第0行可以当做没选

dp[2][j][k]=bj[1][j]+bj[2][k] bj数组的意义同下文

则当i>2时 dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][l]+bj[i][j])

其中l是枚举的倒数第三行的状态编号,bj[i][j]表示第i行的第j个状态放了多少个

上代码

 

#include<iostream>
#include<cstdio>
#include<cstring>
#define int long long
using namespace std;
int num[105][(1<<10)+1],bj[105][(1<<10)+1],ans,n,m,mapp[105][15],dp[105][(1<<10)+1][(1<<10)+1];
bool check(int r,int x)

    for(int i=m;i>=1;i--)
    
        if(!mapp[r][i]&&(x&1))return false;
        x>>=1;
    
    return true;
//检查状态是否合法
int getnum(int r,int x)

    int res=0;
    while(x)res+=x&1,x>>=1;
    return bj[r][num[r][0]]=res;
//初始化bj数组
signed main()

    scanf("%lld%lld",&n,&m);
    char ch;
    for(int i=1;i<=n;i++)
    
        for(int j=1;j<=m;j++)
        
            cin>>ch;
            if(ch==P)mapp[i][j]=1;
            else mapp[i][j]=0;
        
    
    int maxn=(1<<m)-1;
    for(int i=1;i<=n;i++)
    
        for(int j=0;j<=maxn;j++)
        
            if(check(i,j)&&!(j&(j<<1))&&!(j&(j<<2)))
            
                num[i][++num[i][0]]=j;//num[i][j]表示第i行编号为j的状态是什么,num[i][0]表示这一行有多少个合法状态
                if(i==1)dp[i][num[i][0]][0]=getnum(i,j);
                bj[i][num[i][0]]=getnum(i,j);
            
        
    
    for(int i=1;i<=num[2][0];i++)
    
        for(int j=1;j<=num[1][0];j++)
        
            int x=num[2][i],y=num[1][j];
            if(x&y)continue;
            dp[2][i][j]=max(dp[2][i][j],bj[2][i]+bj[1][j]);
        
    //枚举上下两行,初始化dp[2]
    for(int i=3;i<=n;i++)
    
        for(int j=1;j<=num[i][0];j++)
        
            for(int k=1;k<=num[i-1][0];k++)
            
                for(int l=1;l<=num[i-2][0];l++)
                
                    int x=num[i][j],y=num[i-1][k],z=num[i-2][l];
                    if((x&y)||(y&z)||(x&z))continue;
                    dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][l]+bj[i][j]);
                
            
        
    //枚举这一行、上一行、上上行
    for(int i=1;i<=num[n][0];i++)
    
        for(int j=1;j<=num[n-1][0];j++)
        
            int x=num[n][i],y=num[n-1][j];
            if(x&y)continue;
            ans=max(ans,dp[n][i][j]);
        
    //枚举这一行和上一行的可能
    printf("%lld",ans);
    return 0;

 

以上是关于2019.9.1 炮兵阵地的主要内容,如果未能解决你的问题,请参考以下文章

炮兵阵地

洛谷P2704 炮兵阵地

[poj1185]炮兵阵地_状压dp

动态规划-状压DP(炮兵阵地)

炮兵阵地经典状压dp

炮兵阵地