洛谷P2704_状压dp

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

int n, m;
int a[111];//将每一行处理为一串二进制数
int num[1<<10];//预处理数组
int dp[3][1<<10][1<<10];//point!!滚动数组,防止MLE

int getnum(int x)
{
    int ret = 0;
    while(x)
    {
        if(x&1) ++ret;
        x >>= 1;
    }
    return ret;
}

int main()
{
    int i, j, R, S, T;//R:当前行,S:上一行,T:上上一行
    char ch;
    cin >> n >> m;
    memset(a, 0, sizeof(a));
    for(i = 0; i < n; ++i)
        for(j = 0; j < m; ++j)
    {
        cin >> ch;
        a[i] <<= 1;
        a[i] += (ch=='H'?1:0);
    }
    for(i = 0; i < (1<<m); ++i) num[i]=getnum(i);//初始化num数组
    for(R = 0; R < (1<<m); ++R)//初始化第一行
        if(!(R&a[0]) && !(R&(R<<1)) && !(R&(R<<2)))
            dp[0][R][0] = num[R];
    for(S = 0; S < (1<<m); ++S)//初始化第二行
        for(R = 0; R < (1<<m); ++R)
            if(!(R&S) && !(R&a[1]) && !(R&(R<<1)) && !(R&(R<<2)) && !(S&a[0]) && !(S&(S<<1)) && !(S&(S<<2)))
                dp[1][R][S] = num[R] + num[S];
    for(i = 2; i < n; ++i)//从第三行开始枚举行数
        for(T = 0; T < (1<<m); ++T)//枚举上上行
        {
            if(T&a[i-2] || T&(T<<1) || T&(T<<2)) continue;
            for(S = 0; S < (1<<m); ++S)//枚举上一行
            {
                if(S&a[i-1] || S&(S<<1) || S&(S<<2) || T&S) continue;
                for(R = 0; R < (1<<m); ++R)//枚举当前行
                {
                    if(R&a[i] || R&(R<<1) || R&(R<<2)|| R&T || R&S)
                        continue;
                    dp[i%3][R][S] = max(dp[i%3][R][S], dp[(i-1)%3][S][T]+num[R]);//更新状态
                }
            }
        }
    int ans = 0;
    for(S = 0; S < (1<<m); ++S)
        for(R = 0; R < (1<<m); ++R)
            ans = max(ans, dp[(n-1)%3][R][S]);
    printf("%d\n", ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jay__bryant/article/details/80352653