感觉上很难,确实自己做一开始没有想到是dp问题,同时没有进行剪枝,同时有一些准备工作没有做好
- 没有提前将每一行的信息转成数字信息(做题经验不足)
- 没有提前把每行可能的情况抽取出来
- 没有想到其实确实是一个dp问题(其实一开始的贪心思路有些不太对)
判断贪心和dp问题的一个方法可以是看数据范围
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int dp[105][65][65]; int cnt=0; int str[65]; int sum[65]; int map[110]; char s[110][110]; bool check(int x)//判断这个排列是否为普通的合法序列 { if(x&(x<<1)) return false; if(x&(x<<2)) return false; return true; } int getSum(int x)//当前状态的炮兵数目 { int ans=0; while(x>0) { if(x&1) ans++; x>>=1; } return ans; } void before_hand(int mid)//预处理出所有的可能合法炮兵状态,cnt统计状态数 { for(int i=0;i<(1<<mid);i++) { if(check(i)) { str[cnt]=i;//str数组记录状态,dp中的j和k都是str数组的下标 sum[cnt]=getSum(i); cnt++; } } } int main() { int n,m; scanf("%d%d",&n,&m); memset(dp,-1,sizeof dp); for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { char a; cin >> a; if(a=='H') map[i]|=(1<<j);//统计每一行的不合法格子状态 } } before_hand(m);//其实可以不传参 for(int i=0;i<cnt;i++) { if(!(str[i]&map[0])) dp[0][0][i]=sum[i];//先处理出第一行的情况 } for(int r=1;r<n;r++)//枚举行数 { for(int i=0;i<cnt;i++)//枚举当前行的排列 { if(str[i]&map[r]) continue; for(int j=0;j<cnt;j++)//枚举上一行的排列情况 { if(str[i]&str[j]) continue; for(int k=0;k<cnt;k++)//枚举i-2行的排列情况 { if(str[i]&str[k]) continue; if(dp[r-1][k][j]==-1) continue; dp[r][j][i]=max(dp[r][j][i],dp[r-1][k][j]+sum[i]);//更新即可 } } } } int ans=0;//统计答案 for(int i=0;i<cnt;i++) { for(int j=0;j<cnt;j++) { ans=max(ans,dp[n-1][i][j]); } } printf("%d\n",ans); return 0; }
标签:int,1185,炮兵阵地,POJ,65,ans,include,dp,110 From: https://www.cnblogs.com/ymx10086/p/17069156.html