现在的位置: 首页 > 算法 > 正文

poj 1185 状态压缩DP

2019年02月27日 算法 ⁄ 共 1718字 ⁄ 字号 评论关闭

思路:首先做个预处理,把每一行可以放的状态存起来,以后就可以只看这么多状态而不是for全看一遍了。

之后,因为放一个可以影响四个方向2格,所以第i行的状态和i-1行i-2行有关系的,通过之前的状态来推,状态转移方程可以写为:

dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][l]+f[i][j])

这里i代表第i行,j为第i行的状态,k为第i-1行状态,l为i-2行状态,f[i][j]表示第i行在j状态下放的个数。

记得前两行特殊处理下。

这里直接开数组会MLE,所以用滚动数组来。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<string>
#include<algorithm>
#include<queue>
using namespace std;
char a[111][15];
int f[111][1025];
int dp[3][1025][1025];
int m,n;
vector<int>g[111];
void pre()
{
    int l=(1<<m);
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<l;j++)
        {
            int cnt=-1;
            int r=j;
            bool flag=0;
            int num=0;
            for(int k=0;k<=m;k++)
            {
                if(r%2)
                {
                    if(cnt!=-1&&cnt<2)
                    {
                        flag=1;
                        break;
                    }
                    if(a[i][k]=='H')
                    {
                        flag=1;
                        break;
                    }
                    num++;
                    cnt=0;
                }
                else if(cnt!=-1)cnt++;
                r/=2;
            }
            if(flag==0)
            {
                g[i].push_back(j);
                f[i][j]=num;
            }
        }
    }
}
void solve()
{
    if(n==1)
    {
        int ans=0;
        for(int i=0;i<g[0].size();i++)ans=max(ans,f[0][g[0][i]]);
        printf("%d\n",ans);
    }
    else
    {
        int ans=0;
        memset(dp,0,sizeof(dp));
        int x=g[0].size();
        int y=g[1].size();
        int z;
        for(int i=0;i<x;i++)
        {
            for(int j=0;j<y;j++)
            {
                if((g[0][i]&g[1][j])==0)
                {
                    dp[0][g[1][j]][g[0][i]]=max(dp[0][g[1][j]][g[0][i]],f[0][g[0][i]]+f[1][g[1][j]]);
                    ans=max(ans,dp[0][g[1][j]][g[0][i]]);
                }
            }
        }
        for(int i=2;i<n;i++)
        {
            x=g[i].size();
            y=g[i-1].size();
            z=g[i-2].size();
            for(int j=0;j<x;j++)
            {
                for(int k=0;k<y;k++)
                {
                    if(g[i][j]&g[i-1][k])continue;
                    for(int l=0;l<z;l++)
                    {
                        if(g[i][j]&g[i-2][l])continue;
                        if(g[i-1][k]&g[i-2][l])continue;
                        dp[1][g[i][j]][g[i-1][k]]=max(dp[1][g[i][j]][g[i-1][k]],dp[0][g[i-1][k]][g[i-2][l]]+f[i][g[i][j]]);
                        ans=max(ans,dp[1][g[i][j]][g[i-1][k]]);
                    }
                }
            }
            for(int j=0;j<x;j++)
            {
                for(int k=0;k<y;k++)
                {
                    dp[0][g[i][j]][g[i-1][k]]=dp[1][g[i][j]][g[i-1][k]];
                }
            }
            memset(dp[1],0,sizeof(dp[1]));
        }
        printf("%d\n",ans);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)scanf("%s",a[i]);
    pre();
    solve();
    return 0;
}

抱歉!评论已关闭.