[codevs1647]炮兵阵地

来源:互联网 发布:mysql主键从1开始 编辑:程序博客网 时间:2024/06/06 04:04

乍看这题,差不多理清要枚举上层和上上层……
然而……,1000^3能过?!
然后发现许多状态预处理时就能删掉……统共合理的(没有相邻1)的情况不过100+

于是预处理出前两层的答案
转移时三层枚举

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int MAXN = 125 + 50;int dp[MAXN][MAXN][MAXN],num[MAXN];int vis[11];int digit[MAXN],tot,n,m;void init(){    for(int i = 1;i <= 4048;i ++)    {        int w = 0,cnt = 0;        bool flag = true;        memset(vis,0,sizeof(vis));        while((1 << w) <= i)        {            if(i & (1 << w))            {                vis[w] = true;                cnt ++;                if(vis[w - 1] || vis[w - 2])                {                    flag = false;                    break;                }            }            w ++;        }        if(!flag)continue;        digit[++ tot] = i;        num[tot] = cnt;    }}char s[1001];int mp[1001],ans;int main(){    init();    memset(dp,-1,sizeof(dp));    scanf("%d%d",&n,&m);    for(int i = 1;i <= n;i ++)    {        scanf("%s",s);        for(int j = 0;j < m;j ++)        {            if(s[j] == 'H')            {                mp[i] += (1 << j);            }        }    }    for(int i = 1;i <= tot && digit[i] < (1 << m);i ++)    {        for(int j = 1;j <= tot && digit[j] < (1 << m);j ++)        {            int tmp1 = digit[i];            int tmp2 = digit[j];            if((!(tmp1 & tmp2)) && (!(tmp1 & mp[2])) && (!(tmp2 & mp[1])))            {                dp[2][i][j] = num[i] + num[j];                ans = max(ans,dp[2][i][j]);            }        }    }    for(int k = 3;k <= n;k ++)    {        for(int i = 0;i <= tot && digit[i] < (1 << m);i ++)        {            if(digit[i] & mp[k - 1])continue;            for(int j = 0;j <= tot && digit[j] < (1 << m);j ++)            {                if(digit[j] & mp[k - 2])continue;                if(dp[k - 1][i][j] == -1)continue;                //dp[k][0][i] = max(dp[k][0][i],dp[k - 1][i][j]);                for(int t = 0;t <= tot && digit[t] < (1 << m);t ++)                {                    if(!(digit[t] & mp[k]) && (!(digit[t] & digit[i])) && (!(digit[t] & digit[j])))                    {                        dp[k][t][i] = max(dp[k][t][i],num[t] + dp[k - 1][i][j]);                        ans = max(ans,dp[k][t][i]);                    }                }            }        }    }    printf("%d",ans);    return 0;}

还有一份wwq大佬的代码,预处理略微不同,判断是否有相邻1时更机智

#include<cstdio>#include<cstring>#include<iostream>using namespace std;const int MAXN=100+5;int f[MAXN][100][100],mp[MAXN],sav[100],num[100];char ch[12];int n,m,cnt;bool check(int x){    if((x&(x<<1))||(x&(x<<2))) return 0;    return 1;}void read(int& x){    char c;    x=0;    for(c=getchar();c!='P'&&c!='H';c=getchar());    for(int i=0;c=='P'||c=='H';c=getchar(),++i)        if(c=='H')            x|=(1<<i);}int main(){    scanf("%d%d",&n,&m);    for(int i=1;i<=n;++i)        read(mp[i]);    for(int i=0;i<1<<m;++i)        if(check(i))        {            sav[++cnt]=i;            for(int j=0;j<m;++j)                if(i&(1<<j))                    ++num[cnt];        }           for(int i=1;i<=cnt;++i)        if(!(sav[i]&mp[1]))            f[1][i][1]=num[i];    for(int i=2;i<=n;++i)        for(int j=1;j<=cnt;++j)        {            if(sav[j]&mp[i]) continue;            for(int k=1;k<=cnt;++k)            {                if((sav[k]&mp[i-1])||(sav[j]&sav[k]))                    continue;                for(int w=1;w<=cnt;++w)                {                    if((sav[w]&mp[i-2])||(sav[w]&sav[j])||(sav[w]&sav[k]))                        continue;                    f[i][j][k]=max(f[i][j][k],f[i-1][k][w]+num[j]);                }            }        }    int ans=0;    for(int i=1;i<=cnt;++i)    {        if(mp[n]&sav[i]) continue;        for(int j=1;j<=cnt;++j)        {            if(!(mp[n-1]&sav[j])&&!(sav[i]&sav[j]))                ans=max(ans,f[n][i][j]);        }    }    printf("%d",ans);    return 0;}
原创粉丝点击