您的位置:首页 > 其它

POJ 1185 炮兵阵地 (状态压缩dp)

2016-07-17 22:29 363 查看
这题的状态我是这样定义的:

dp[i][j][k] 表示在第k行前,当前状态是i,上一行的状态是j的时候,最多可以放多少个炮。

一开始我定义的时候,没有中间那个j,但是后来想想似乎不对。

如果这样定义的话,碰到这种情况就不对了。

HPH

PHP

HPH

第三行,按照(错误)定义,是从第二行来的,第二行是从第一行来。

但是这时的第三行和第一行明显不可以同时存在于第二列上。

这样的定义就会算进去,会错误。

所以需要多加一维。

另外这题i,j并不是真正的状态,而是状态集合的下标。

因为通过运算,发现,一行最多只有60种可行情况。

所以数组不需要开到1<<10这样大,只要开比60多就行了。

代码如下:

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
using namespace std;

char grid[120][12];
int able[100][120];
int pt[120];
int dp[100][100][120];
int n,m;

void init()
{
memset(grid,0,sizeof(grid));
memset(able,0,sizeof(able));
memset(pt,0,sizeof(pt));
memset(dp,0,sizeof(dp));
}

bool test1(int now,int row)
{
for(int i=m-1;i>=0;i--)
{
if(now%2==1 && grid[row][i]=='H') return false;
now=now/2;
}
return true;
}

int test2(int S)
{
return (((S<<1)&S) | ((S<<2)&S));
}

int bitcount(int S)
{
int cnt=0;
/*while(S>0)
{
cnt+=(S&1);
S=(S>>1);
}*/
while(S>0)
{
if(S%2==1) cnt++;
S=S/2;
}
return cnt;
}

int main()
{
while(cin>>n>>m)
{
init();
for(int i=0;i<n;i++)
{
scanf("%s",grid[i]);
}

for(int i=0;i<n;i++)
{
for(int S=0;S<(1<<m);S++)
{
if(test1(S,i)==false) continue;
if(test2(S)!=0) continue;
able[pt[i]][i]=S;
pt[i]++;
}
}
//printf("%d\n",pt[0]);

//枚举第一行
for(int i=0;i<pt[0];i++)
{
int S=able[i][0];
dp[i][0][0]=bitcount(S);
}

//枚举第二行
for(int i=0;i<pt[1];i++)
{
int S=able[i][1];
for(int j=0;j<pt[0];j++)
{
int P=able[j][0];
if( (P&S)!=0 ) continue;
dp[i][j][1]=max(dp[i][j][1],dp[j][0][0]+bitcount(S));
}
}

//正式开始
for(int r=2;r<n;r++)
{
for(int i=0;i<pt[r];i++)
{
int S=able[i][r];
for(int j=0;j<pt[r-1];j++)
{
int P=able[j][r-1];
if((P&S)!=0) continue;
for(int k=0;k<pt[r-2];k++)
{
int T=able[k][r-2];
if((T&S)!=0 || (P&T)!=0) continue;
dp[i][j][r]=max(dp[i][j][r],dp[j][k][r-1]+bitcount(S));
}
}
}
}

int ans=0;
for(int i=0;i<100;i++)
{
for(int j=0;j<100;j++)
{
ans=max(ans,dp[i][j][n-1]);
}
}
printf("%d\n",ans);

}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: