标签:表示 turn 处理 滚动 std tac string back 一个
这个题是一个经典的状压dp,m<=10,意味着我们可以将每一层的状态压起来,提前预处理好,然后枚举当前在哪一层和i层 i-1层 i-2层的状态,理论上来说,这样最坏的时间复杂度是O(2^3m*n),但是因为障碍物的存在,以及预处理当中对左右格子的判断,时间复杂度会大大优于最坏情况,所以能够卡着过
#include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<queue> #include<stack> #include<cmath> using namespace std; vector<int>mmp[110]; char s[15]; int di[110],n,m,dp[2][1030][1030],tail,ans; inline void init()//预处理好所有能够成为状态的方案,按层存起来 { for(int i=0;i<=(2<<(m-1))-1;i++) { if(!((i>>1)&i)&&!((i>>2)&i)&&!((i<<1)&i)&&!((i<<2)&i))//左右两格不能有棋子 { for(int j=1;j<=n;j++) { if(!(di[j]&i))//不能与地形有冲突 mmp[j].push_back(i); } } } } inline int get(int x)//数数这个状态有多少棋子 { int re=0; while(x) { if(x&1) re++; x>>=1; } return re; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%s",s+1); for(int j=1;j<=m;j++)//先把地图压起来 { if(s[j]==‘H‘) di[i]|=(1<<(m-j)); } } init(); for(int i=0;i<mmp[1].size();i++)//提前预处理好前两层状态,方便下面运算 for(int j=0;j<mmp[2].size();j++) if(!(mmp[1][i]&mmp[2][j])) dp[0][mmp[1][i]][mmp[2][j]]=max(dp[0][mmp[1][i]][mmp[2][j]],get(mmp[1][i])+get(mmp[2][j])); for(int i=3;i<=n;i++)//枚举现在到了第几层 { tail=1-tail;//滚动数组的小技巧 for(int j=0;j<mmp[i-2].size();j++)//枚举前两层状态 for(int k=0;k<mmp[i-1].size();k++) { if(!(mmp[i-2][j]&mmp[i-1][k]))//一个小优化 { for(int l=0;l<mmp[i].size();l++)//枚举现在的状态 { if(!(mmp[i-2][j]&mmp[i][l])&&!(mmp[i-1][k]&mmp[i][l]))//三行的炮兵都不能攻击到对方 { dp[tail][mmp[i-1][k]][mmp[i][l]]=max(dp[tail][mmp[i-1][k]][mmp[i][l]],dp[1-tail][mmp[i-2][j]][mmp[i-1][k]]+get(mmp[i][l])); ans=max(ans,dp[tail][mmp[i-1][k]][mmp[i][l]]);//dp[i][j][k]表示当前在第 i层,i-1层选的方案:j,i层选的k,第一维可以滚动掉 } } } } } printf("%d",ans); }
标签:表示 turn 处理 滚动 std tac string back 一个
原文地址:http://www.cnblogs.com/Loi-dfkdsmbd/p/7752914.html