HDU

来源:互联网 发布:淘宝网溜冰鞋儿童 编辑:程序博客网 时间:2024/06/10 04:43
题目描述:

点击打开链接

这个题与我上一篇博客讲的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;                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;}