您的位置:首页 > 其它

HDU - 4539 郑厂长系列故事——排兵布阵(POJ 3254变形题)

2017-09-08 10:09 253 查看
题目描述:
点击打开链接

这个题与我上一篇博客讲的POJ 3254那个题是十分相似的,无非这个题是求人数,人数处理其实比方案数容易,只需要把每种状态的人数预处理出来,最后找最大的就好了。麻烦的是这题要求的曼哈顿距离为2的点不能同时站人,那么意味着我们按行枚举时,需要枚举前两行的状态,这样我们的dp数组需要开到三维,并且会增加我们的循环层数,所以一开始我担心MLE,TLE的问题并不是很敢用DP写,但后来也没想到什么更好的方法,于是还是采取了状压DP,这题列数最多达到了15列,也就是极限情况最多会有2^15个状态,这么大的数组显然是开不出来的,但是由于我们要筛选可行状态,我们需要大致估计有多少可行状态,仔细思考一下会发现其实可行的状态其实并不多,我一开始后两维开的220,果断MLE,调过几次之后就AC了.

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<stack>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
const int MAXM=170;

int n,m;
int dp[MAXM][MAXM][MAXM],e[MAXM],s[MAXM],c[MAXM];

int cal(int state)
{
int res=0;
while(state)
{
if (state&1)
res++;
state=state>>1;
}
return res;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
if (n==0||m==0)
{
printf("0\n");
continue;
}
memset(e,0,sizeof(e));
int x;
for (int i=0;i<n;i++)
{
for (int j=0;j<m;j++)
{
scanf("%d",&x);
if (!x)
e[i]=e[i]|(1<<j);
}
}
int cnt=0;
for (int i=0;i<(1<<m);i++)
{
if (i&(i<<2)) continue;
s[cnt]=i;
c[cnt]=cal(i);
cnt++;
}
memset(dp,-1,sizeof(dp));
for (int i=0;i<cnt;i++)
{
if (s[i]&e[0]) continue;
dp[0][i][0]=c[i];
}
for (int i=1;i<n;i++)
{
for (int j=0;j<cnt;j++)
{
if (e[i]&s[j]) continue;

4000
for (int k=0;k<cnt;k++)
{
if ((s[j]&(s[k]<<1))||(s[j]&(s[k]>>1)))
continue;
for (int l=0;l<cnt;l++)
{
if (s[l]&s[j]) continue;
if ((s[k]&(s[l]<<1))||(s[k]&(s[l]>>1)))
continue;
if (dp[i-1][k][l]==-1)
continue;
dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][l]+c[j]);
}
}
}
}
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: