POJ 1185 经典状压dp

做了很久的题 有注释

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<math.h>
using namespace std;
int dp[107][107][107];///二维记录上一次 三维记录此次
///dp[i][k][j]=max(dp[i][k][j],dp[i-1][t][k])+num[j]; t为枚举数且满足与 k j 的条件
///初始化can num数组减少时间
///如果不使用can数组来记录 memset都会超时
int can[107];
int num[107];
int n,m;
int c[107];
char s[107];
bool ok(int x)
{
    if(x&(x<<1))
        return false;
    if(x&(x<<2))
        return false;
    return true;
}
int main(){
while(~scanf("%d%d",&n,&m))
{
    for(int i=0;i<n;i++)
    {
        scanf("%s",s);
        c[i]=0;
        for(int k=0;k<m;k++)
        {
            if(s[k]=='H')     
                c[i]+=(1<<k);
        }
    }
    int w=0;
    memset(dp,-1,sizeof(dp));
    for(int i=0;i<(1<<m);i++)
    {
        if(ok(i))
        {
            can[w]=i;
            int x=can[w];
            num[w]=0;
            while(x>0)
            {
                if(x&1)num[w]++;
                x>>=1;
            }
            w++;
        }
    }
    for(int i=0;i<w;i++)
    {
        if(!(can[i]&c[0])) ///得满足条件才能放
        dp[0][0][i]=num[i];
    }
    for(int i=1;i<n;i++)
    {
        for(int j=0;j<w;j++)
        {
            if(c[i]&can[j])
                continue;
            for(int k=0;k<w;k++)
            {
                if(can[j]&can[k])
                    continue;
                for(int t=0;t<w;t++)
                {
                    if(can[j]&can[t]||can[k]&can[t])
                        continue;
                    if(dp[i-1][t][k]==-1) ///如果上一行等于-1说明不满足条件 
                        continue;
                    dp[i][k][j]=max(dp[i][k][j],dp[i-1][t][k]+num[j]);
                }
            }
        }
    }
    int ans=0;
    for(int k=0;k<n;k++)
    for(int i=0;i<w;i++)
    for(int j=0;j<w;j++)
    {
        ans=max(ans,dp[k][i][j]);
    }
    printf("%d
",ans);
}
}

  

原文地址:https://www.cnblogs.com/rayrayrainrain/p/5406604.html