***POJ1185 炮兵阵地 ACM解题报告(状压dp入门题)

来源:互联网 发布:安装虚拟linux系统 编辑:程序博客网 时间:2024/06/06 04:14

这题是个入门的状压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 105typedef 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;}


0 0