POJ1185 炮兵阵地 状态压缩DP
2017-08-26 12:57
344 查看
这题是个入门的状压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,位运算优先级低,一定要加括号(我就是被拿了学长写的代码然后没加括号,看了一下午。。。虽然自己也有个手误。)
附上我的代码:
调试了好久才过,错误原因在于没完全认清楚DP的表示意义,混用。比如init那里用legal表示i,j
下面状态转移又用I,J
另外上面下面全用legal会超时
注意点挺多的,首先是要开数组记录所有情况,然后记录每种情况的炮兵数,很多处理类似于前一题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 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; }
附上我的代码:
#include<string> #include<string.h> #include<iostream> #include<stdio.h> using namespace std; int map[101]={0}; //每一行的地图 int legal[101]; //合法状态 int n 9945 um[101]; //某合法状态的炮兵数 int p=0; int dp[101][101][101]; int max(int x,int y) {return x>y?x:y; } bool judge(int x) //判断x是否合法 { if(x&(x<<1)) return false; if(x&(x<<2)) return false; return true; } int getcnt(int x) { return x==0?0:getcnt(x>>1)+(1&x); } void init() { for(int i=0;i<p;i++) { if(legal[i]&map[0]) continue; for(int j=0;j<p;j++) dp[0][i][j]=num[i]; } } int main() { memset(dp,-1,sizeof(dp)); int n,m; cin>>n>>m; for(int i=0;i<n;i++) { char tmp[15]; scanf("%s",tmp); for(int j=0;j<m;j++) if(tmp[j]=='H') map[i]+=(1<<j); } for(int i=0;i<(1<<m);i++) if(judge(i)) { legal[p]=i; num[p++]=getcnt(i); } init(); for(int i=1;i<n;i++) for(int j=0;j<p;j++) { if(legal[j]&map[i]) continue; for(int k=0;k<p;k++) { if(legal[k]&map[i-1]) continue; //这句可有可无,因为上面面已经保证过有值得都是符合地图的。有这句的话加快速度 if(legal[j]&legal[k]) continue; for(int h=0;h<p;h++) { if(legal[j]&legal[h]) continue; if(legal[h]&legal[k]) continue; if(dp[i-1][k][h]==-1) continue; dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][h]+num[j]); } } } int maxn=-1; for(int i=0;i<p;i++) for(int j=0;j<p;j++) maxn=max(maxn,dp[n-1][i][j]); cout<<maxn; return 0; }
调试了好久才过,错误原因在于没完全认清楚DP的表示意义,混用。比如init那里用legal表示i,j
下面状态转移又用I,J
另外上面下面全用legal会超时
相关文章推荐
- POJ 1185 炮兵阵地(状态压缩DP)
- POJ 1185 炮兵阵地 状态压缩DP简单题
- poj 1185 状态压缩dp(炮兵阵地)
- poj1185 炮兵阵地 状态压缩dp
- POJ 1185 炮兵阵地 (状态压缩DP)
- POJ 1185 炮兵阵地(状态压缩DP)
- POJ 1185 炮兵阵地 (状态压缩dp)
- 状态压缩 -- POJ 1185 炮兵阵地【状态压缩DP】
- poj 1185 炮兵阵地 状态压缩DP
- POJ 炮兵阵地 1185 状态压缩dp
- POJ 1185 炮兵阵地(状态压缩DP)
- poj 1185 炮兵阵地 【状态压缩dp】
- 状态压缩DP-炮兵阵地(POJ 1185)
- poj 1185 炮兵阵地 //状态压缩DP
- poj 1185 炮兵阵地 状态压缩dp
- POJ 1185 炮兵阵地(经典状态压缩dp)
- poj 1185 炮兵阵地 状态压缩dp
- poj1185 炮兵阵地 经典状态压缩dp
- POJ1185 炮兵阵地 状态压缩DP
- 状态压缩dp入门题 POJ 1185 炮兵阵地