牛客周赛 Round 32 F.小红的矩阵修改【三进制状态压缩dp】

news2025/1/21 12:18:30

原题链接:https://ac.nowcoder.com/acm/contest/75174/F

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

小红拿到了一个字符矩阵,矩阵中仅包含"red"这三种字符。

小红每次操作可以将任意字符修改为"red"这三种字符中的一种。她希望最终任意两个相邻的字母都不相同。小红想知道,至少需要修改多少个字符?

输入描述:

第一行输入两个正整数n,m,代表矩阵的行数和列数。
接下来的n行,每行输入一个长度为m的、仅由"red"这三种字符组成的字符串。
1≤n≤4
1≤m≤1000

输出描述:

一个整数,代表需要修改的字母数量的最小值。

示例1

输入

2 3
ree
dee

输出

2

说明

修改为:
red
dre
即可。

解题思路:

我看到这个题目的时候直接就想到了线性dp,直接设f[i][j][0]表示当前位置为'r',f[i][j][1]表示当前位置为'e',f[i][j][1]表示当前位置为'd',时最少的修改次数,可以保证让当前位置和左边和上边都不同,但是我忽略掉了一个问题,就是这样只能保证当前位置所在行和所在列合法,左上角其他部分不一定合法,如下如所示,所以这样dp是不对的,如下图所示:

也就是说我们只能保证当前所在行蓝色部分和当前所在列红色部分合法,但是左上角红色和蓝色相交部分,也就是绿色部分不一定合法,例如当[i,j]为r,[i,j-1]为d,[i-1,j]为e,此时的[i-1][j-1]如果为d那么对于[i-1,j]合法,但是会导致[i,j-1]不合法了,此时的[i-1,j-1]如果为e那么对于[i,j-1]合法,但是会导致[i-1,j]不合法,所以说这种dp方式是错误的。

这个题目正解是状态压缩dp,下面考虑状态压缩dp,但是这个题目还有一点特殊的地方,就是常规的状态压缩dp是以列来压缩状态,但是这里的列m非常大,所以不能以列来压缩状态,但是我们可以发现行非常小,我们可以以行来压缩状态,假设有n行,常规情况下是有(1<<n)种状态,但是这里每个位应该有三种状态,所以这里不像常规的状态压缩dp,常规的状态压缩都是二进制压缩,但是这个题目需要三进制压缩,所以有3^n中状态,然后按照二进制压缩dp的模式稍微改一改就行,改成三进制压缩就行了,其他部分都是一样的。

状态压缩dp处理如下:

我们先预处理所有合法状态,然后再考虑状态转移。

状态定义:

定义f[i][j]表示处理完前i列,并且第i列状态为j的最少修改次数。

状态转移:

当前行必须保证任意相邻位置不相同,当前行由前一行转移过来。

a表示当前行变为的状态,b表示前一行的状态,v1表示当前行变为状态a的修改次数

f[i][a]=min(f[i][a],f[i-1][b]+v1)

最终答案:

最终答案肯定是处理完前m-1行,最后一行的状态为某一个合法状态的最小值,j表示某一个合法状态

min(f[m-1][j])

时间复杂度:这个时间复杂度不太好表示,那么就粗略估计一下吧,大概是O(m*(state^2)),state表示合法状态数。

空间复杂度:空间大概为O(m*(3^n)),n表示行数,m表示列数。

cpp代码如下:

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

using namespace std;

const int N=6,M=1010;
int n,m;
char gg[N][M];
int g[N][M];    //映射数组,将原来的red映射为012
vector<int>state;  //存储所有合法状态
vector<int>arrive[100]; //存储每个合法状态的所有合法转移
int p3[5]={1,3,9,27,81}; //存储3的幂
int f[M][100]; //f[i][j]表示处理完前i行,并且第i行状态为j的最少修改次数

bool check(int x)  //检查当前状态x是否合法,合法指的是x的三进制表示所有相邻位都不相同
{
    int last=-1,cnt=n;
    while(cnt--){
        int v=x%3;
        if(v==last)return false;
        x/=3;
        last=v;
    }
    return true;
}

bool check(int x,int y) //判断俩个数的三进制表示是否所有位都不同,
{
    for(int i=0;i<n;i++){
        if(x%3==y%3)return false;
        x/=3,y/=3;
    }
    return true;
}
int a1[4]={};
int main()
{
    cin>>n>>m;
    for(int i=0;i<n;i++)scanf("%s",gg[i]);
    for(int i=0;i<n;i++)//先把red映射为012
        for(int j=0;j<m;j++)
            if(gg[i][j]=='r')g[i][j]=0;
            else if(gg[i][j]=='e')g[i][j]=1;
            else g[i][j]=2;
    for(int i=0;i<p3[n];i++) //首先预处理所有合法状态
    {
        if(check(i))state.push_back(i);
    }
    
    for(int i=0;i<state.size();i++){ //预处理每个合法状态的所有合法转移
        
        for(int j=0;j<state.size();j++)
        {
            //当俩行三进制表示每个位都不同时,才能转移
            if(check(state[i],state[j]))arrive[i].push_back(j);
        }
    }
    memset(f,0x3f,sizeof f);
    for(int i=0;i<m;i++)
    {
        for(int a=0;a<state.size();a++){
            for(int j=0;j<n;j++)a1[j]=0;  //记得a1数组要初始化,不初始化可能会受到前面的影响
            int x=state[a],v1=0,cnt1=0;
            while(x){
                a1[cnt1++]=x%3;
                x/=3;
            }
            for(int j=0;j<n;j++)
                if(g[j][i]!=a1[j])v1++; //计算当前位置变为状态state[a]需要修改多少次
            if(i==0){
                f[i][a]=v1; //第一行前面没有行,所以特殊处理,
                continue;
            }
            for(auto b:arrive[a]){  //前面预处理好了所有合法转移,所以这里直接计算即可
                f[i][a]=min(f[i][a],f[i-1][b]+v1);
            }
        }
    }
    int ans=0x3f3f3f3f;
    //计算答案,非法状态会是一个非常大的值,所以这里我们直接枚举所有状态也不影响答案
    for(int j=0;j<p3[n];j++)
        ans=min(ans,f[m-1][j]);
    cout<<ans<<endl;
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1446860.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

顶级思维方式——认知篇三(心胸与见识)

目录 1、老《三国演义》司马懿 2、司马迁 3、 王立群&#xff1a; 使自己强大起来&#xff0c;这是打破困境的唯一途径 4、鲁迅经典寓言&#xff1a;聪明人、奴才和傻子 5、芒格 6、巴菲特 7、瑞达利欧 8、诸葛亮 1、老《三国演义》司马懿 你等年级轻轻一遇挫折&#x…

蓝桥杯题目解析 --汉诺塔(含C++栈的知识)

该题在蓝桥杯基础数据结构篇&#xff0c;进入后搜索题号1512。 汉诺塔 可以将圆盘临时置于B杆&#xff0c;也可以将A杆移除的圆盘重新移回A杆&#xff0c;但必须遵循上述两条规则。 汉诺塔了解后&#xff0c;题目也了解后&#xff0c;我们先通过试N的个数来找规律&#xff1a;…

Android 10.0 锁屏壁纸 LockscreenWallpaper

前言 一、设置壁纸 通过系统设置进行锁屏壁纸和桌面壁纸的设置。 Setting 部分的代码&#xff1a; packages/apps/WallpaperPicker2/src/com/android/wallpaper/module/DefaultWallpaperPersister.java private int setStreamToWallpaperManagerCompat(InputStream inputStre…

【实战】一、Jest 前端自动化测试框架基础入门(中) —— 前端要学的测试课 从Jest入门到TDD BDD双实战(二)

文章目录 一、Jest 前端自动化测试框架基础入门5.Jest 中的匹配器toBe 匹配器toEqual匹配器toBeNull匹配器toBeUndefined匹配器和toBeDefined匹配器toBeTruthy匹配器toBeFalsy匹配器数字相关的匹配器字符串相关的匹配器数组相关的匹配器异常情况的匹配器 6.Jest 命令行工具的使…

【C语言进阶】深度剖析数据在内存中的存储--上

1. C语言中的数据类型的简单介绍 注&#xff1a;C99标准里面&#xff0c;定义了bool类型变量。这时&#xff0c;只要引入头文件stdbool.h &#xff0c;就能在C语言里面正常使用bool类型。 1.1 在C语言中各类型所占内存空间的大小如下 char类型的数据类型大小为1字节即8比特位。…

爬爬爬——今天是浏览器窗口切换和给所选人打钩(自动化)

学习爬虫路还很长&#xff0c;第一阶段花了好多天了&#xff0c;还在底层&#xff0c;虽然不是我专业要学习的语言&#xff0c;和必备的知识&#xff0c;但是我感觉还挺有意思的。加油&#xff0c;这两天把建模和ai也不学了&#xff0c;唉过年了懒了&#xff01; 加油坚持就是…

16 亚稳态原理和解决方案

1. 亚稳态原理 亚稳态是指触发器无法在某个规定的时间段内到达一个可以确认的状态。在同步系统中&#xff0c;输入总是与时钟同步&#xff0c;因此寄存器的setup time和hold time是满足的&#xff0c;一般情况下是不会发生亚稳态情况的。在异步信号采集中&#xff0c;由于异步…

MySQL篇----第二十二篇

系列文章目录 文章目录 系列文章目录前言一、什么是表级锁二、什么是页级锁三、什么是行级锁四、什么是悲观锁前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 一、…

2023-12蓝桥杯STEMA 考试 Python 中高级试卷解析

蓝桥杯STEMA 考试 Python 中高级试卷&#xff08;12 月&#xff09; 一、选择题 第一题 以下哪项是取余运算符&#xff1f;&#xff08; C &#xff09; A、* B、// C、% D、 第二题 已知&#xff1a;s "python"&#xff0c;执行 print(s[::2])语句后&…

【Java程序设计】【C00265】基于Springboot的地方废物回收机制管理系统(有论文)

基于Springboot的地方废物回收机制管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的地方废物回收机构管理系统 本系统分为管理员功能模块以及员工功能模块。 管理员功能模块&#xff1a;管理员登录系统后…

使用matplotlib库来绘制柱状图

# coding: utf-8 from matplotlib import pyplot as plt from matplotlib import font_manager# 定义区间和宽度列表 interval [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 60, 90] width [5, 5, 5, 5, 5, 5, 5, 5, 5, 15, 30, 60] # 定义数量列表 quantity [836, 2737, 3723, …

【QT+QGIS跨平台编译】之三十六:【RasterLite2+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、RasterLite2介绍二、文件下载三、文件分析四、pro文件五、编译实践一、RasterLite2介绍 RasterLite2是一个开源的轻量级栅格数据库,可以用于存储和管理各种类型的栅格数据,包括卫星遥感图像、数字高程模型等。 与传统的GIS数据存储方式不同,RasterLite2采用基…

【程序设计竞赛】C++与Java的细节优化

必须强调下&#xff0c;以下的任意一种优化&#xff0c;都应该是在本身采用的算法没有任何问题情况下的“锦上添花”&#xff0c;而不是“雪中送炭”。 如果下面的说法存在误导&#xff0c;请专业大佬评论指正 读写优化 C读写优化——解除流绑定 在ACM里&#xff0c;经常出现…

基于Qt的人脸识别项目(功能:颜值检测,口罩检测,表情检测,性别检测,年龄预测等)

完整代码链接在文章末尾 效果展示 代码讲解(待更新) qt图片文件上传 #include <QtWidgets> #include <QFileDialog>

普通男孩的新年创作纪念日

前言 首先在新春佳节&#xff0c;小编在这里祝各位大佬。萌新友友们新年好&#xff0c;希望每一个烟火般的你在新的一年里 offer 多多&#xff0c;薪资多多 &#xff0c;龙行龘龘 &#x1f409; &#x1f409; &#x1f409; &#x1f409;&#xff0c;前程朤朤 ❤️ ❤️ ❤…

Ps:堆栈模式在摄影后期的应用

Photoshop 的堆栈模式 Stack Mode为摄影师提供了一种强大的后期处理能力&#xff0c;通过堆叠和处理多张照片来实现无法单靠一张照片完成的效果。 正确的前期拍摄策略和后期处理技巧可以显著提高最终图像的质量和视觉冲击力。 ◆ ◆ ◆ 前期拍摄通用注意事项 在前期拍摄时&am…

【排序】快速排序

基本思想 快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法&#xff0c;其基本思想为&#xff1a;任取待排序元素序列中的某元素作为基准值&#xff0c;按照该排序码将待排序集合分割成两子序列&#xff0c;左子序列中所有元素均小于基准值&#xff0c;右子序列中所…

视频讲解:优化柱状图

你好&#xff0c;我是郭震 AI数据可视化 第三集&#xff1a;美化柱状图&#xff0c;完整视频如下所示&#xff1a; 美化后效果前后对比&#xff0c;前&#xff1a; 后&#xff1a; 附完整案例源码&#xff1a; util.py文件 import platformdef get_os():os_name platform.syst…

STM32 寄存器操作 GPIO 与中断

一、如何使用stm32寄存器点灯&#xff1f; 1.1 寄存器映射表 寄存器本质就是一个开关&#xff0c;当我们把芯片寄存器配置指定的状态时即可使用芯片的硬件能力。 寄存器映射表则是开关的地址说明。对于我们希望点亮 GPIO_B 的一个灯来说&#xff0c;需要关注以下的两个寄存器…