洛谷P2704_状压dp

本文详细解析了洛谷平台上的P2704题目,通过使用动态规划和状态压缩的技术来求解问题。文章深入探讨了如何将问题转化为二进制表示,并利用动态规划的状态转移方程进行优化,降低时间复杂度,提高算法效率。
摘要由CSDN通过智能技术生成
#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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值