您的位置:首页 > 其它

poj 1185 炮兵阵地(状压dp)

2016-02-15 17:47 330 查看
题目链接:http://poj.org/problem?id=1185

状压dp跑了375ms...

状态转移方程是参考网上的思路...

dp[i][j][k]表示第i行状态为j,第i-1行状态为k的最优解

开一个三维数组,而大小为2*1<<15*1<<15,肯定会MLE

如果筛选出同一行内的可行状态,其实最多只有60种(可以取m最大输出stateNum即可)

状态转移方程为dp[r%2][i][j]=max(dp[r%2][i][j],dp[(r-1)%2][j][k]+num[i]);(滚动数组优化空间)

初始化:

num[i]表示状态i中1的个数,即炮车的数量

则dp[1][i][1]=num[i];

然后枚举就可以了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int INF=0x3f3f3f3f;
const int maxn=105;
int T,n,m;
int map[maxn],state[maxn],num[maxn];
int dp[2][maxn][maxn];//dp[i][j][k]表示第i行状态为j,第i-1行状态为k的最优解
int stateNum;

inline bool ok1(int x){//判断x状态是否可行
return !(x&(x<<1))&&!(x&(x<<2));
}

inline bool ok2(int x,int y){//判断x状态与第y行状态是否可行
return !(x&map[y]);
}

inline int getNum(int x){
int ans=0;
while(x){
ans+=x%2;
x>>=1;
}
return ans;
}

void init(){
memset(dp,-1,sizeof(dp));
memset(map,0,sizeof(map));
stateNum=0;
int cnt=(1<<m);
for(int i=0;i<cnt;i++){//筛选具有满足横向的可行状态
if(ok1(i)){
num[++stateNum]=getNum(i);
state[stateNum]=i;
}
}
}

int main(){
while(~scanf("%d%d",&n,&m)){
init();
char s[maxn];
for(int i=1;i<=n;i++){
scanf("%s",s);
for(int j=0;j<m;j++){
if(s[j]=='H')
map[i]|=(1<<j);
}
}
for(int r=1;r<=n;r++){
for(int i=1;i<=stateNum;i++){//枚举第i行的状态
if(!ok2(state[i],r)) continue;
if(r==1){
dp[1][i][1]=num[i];
}
else{
for(int j=1;j<=stateNum;j++){//枚举第i-1行的状态
if(!ok2(state[j],r-1)) continue;
if(state[i]&state[j]) continue;
for(int k=1;k<=stateNum;k++){//枚举第i-2行的状态
if(state[i]&state[k]) continue;
if(dp[(r-1)%2][j][k]==-1) continue;
dp[r%2][i][j]=max(dp[r%2][i][j],dp[(r-1)%2][j][k]+num[i]);
}
}
}
}
}
int ans=0;
for(int i=1;i<=stateNum;i++){
for(int j=1;j<=stateNum;j++){
ans=max(ans,dp[n%2][i][j]);
}
}
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: