这题是个入门的状压dp(虽然对我来说好难啊,坑了一下午终于过了。。。)难得一个中文题,还这么难
注意点挺多的,首先是要开数组记录所有情况,然后记录每种情况的炮兵数,很多处理类似于前一题3254,可以参考,不过这题更难一点,因为需要考虑两行。
所以得开个三维数组记录情况,d[i][j][k],i是当前行数,j是第i行的情况,k是i-1行的情况。
状态转移方程:d[i][j][k]=max(d[i][j][k],d[i-1][k][h]+num[j]),需要注意几个限制state[j]&b[i]==0,state[j]&state[k]==0,state[j]&state[h]==0,边界是d[0][j][k]=num[j]。
其中需要注意的是num数组是记录每种情况有多少个炮兵,就是要记录一个二进制数之中有多少个1,位运算优先级低,一定要加括号(我就是被拿了学长写的代码然后没加括号,看了一下午。。。虽然自己也有个手误。)
#include<iostream> #include<cstdio> #include<cctype> #include<cstdlib> #include<cmath> #include<algorithm> #include<cstring> #include<string> #include<vector> #include<queue> #include<map> #include<set> #include<sstream> #include<stack> using namespace std; #define MAX 105 typedef long long LL; const double pi=3.141592653589793; const int INF=1e9; const double inf=1e20; const double eps=1e-6; int top,b[105],d[105][100][100];//第一维是第i行,第二维是第i行的状态,第三维是i-1行的状态,存储的是能有多少个炮兵 int state[100];//记录一行上满足条件的总的情况种类 int num[100];//记录每种情况有多少个炮兵 int n,m; bool ok(int x){ if(x&(x<<1)) return false;//相邻2隔内不能有炮兵 if(x&(x<<2)) return false; return true; } int bitcount(int x) { return x == 0 ? 0 : bitcount(x/2) + (x&1);//&优先级低,要加括号(ps.被学长阴掉了) } void init(){ int total=(1<<m); top=0; for(int i=0;i<total;i++){ if(ok(i)){ num[top]=bitcount(i); state[top++]=i; } } } bool fit(int x,int y){ if(x&b[y]) return false; return true; } int main(){ char a[105][20]; cin>>n>>m; init(); memset(b,0,sizeof(b)); memset(d,-1,sizeof(d)); for(int i=0;i<n;i++){ getchar(); scanf("%s",a[i]); for(int j=0;j<m;j++){ if(a[i][j]=='H') b[i]+=(1<<j); } } for(int i=0;i<top;i++){ if(fit(state[i],0)){ for(int j=0;j<top;j++){ d[0][i][j]=num[i];//第一行的情况 } } } int maxn=0; for(int i=1;i<n;i++){ for(int j=0;j<top;j++){ if(fit(state[j],i)){//i行满足的情况 for(int k=0;k<top;k++){ if(state[j]&state[k]) continue; for(int h=0;h<top;h++){//i-2行满足的情况 if(state[h]&state[j]) continue; if(state[h]&state[k]) continue; if(d[i-1][k][h]==-1) continue; d[i][j][k]=max(d[i][j][k],d[i-1][k][h]+num[j]); } } } } } for(int i=0;i<n;i++){ for(int j=0;j<top;j++){ for(int k=0;k<top;k++) if(maxn<d[i][j][k]) maxn=d[i][j][k];//一定要枚举所有情况,如果只有一行的话,最大值就在第一行里,不能在上面计算过程中 找maxn } } printf("%d\n",maxn); return 0; }