标签:turn 初始 记录 ios target namespace name ref color
明显状压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; }
标签:turn 初始 记录 ios target namespace name ref color
原文地址:https://www.cnblogs.com/qxds/p/11443399.html