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

原题链接: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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C# CAD交互界面-自定义面板集-查找定位(六)

运行环境 vs2022 c# cad2016 调试成功 一、代码说明 1. 类成员变量声明&#xff1a; List<ObjectId> objectIds new List<ObjectId>(); // 用于存储AutoCAD实体对象的ObjectId列表 private static Autodesk.AutoCAD.Windows.PaletteSet _ps2; // 自定义浮动面板…

Spring Boot 笔记 006 创建接口_注册

1.1 由于返回数据都是以下这种格式&#xff0c;那么久再编写一个result实体类 报错了&#xff0c;原因是没有构造方法 可以使用lombok的注解自动生成&#xff0c;添加无参的构造器和全参的构造器 package com.geji.pojo;import lombok.AllArgsConstructor; import lombok.NoArg…

《UE5_C++多人TPS完整教程》学习笔记2 ——《P3 多人游戏概念(Multiplayer Concept)》

本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P3 多人游戏概念&#xff08;Multiplayer Concept&#xff09;》 的学习笔记&#xff0c;该系列教学视频为 Udemy 课程 《Unreal Engine 5 C Multiplayer Shooter》 的中文字幕翻译版&#xff0c;UP主&#xff08;也是译…

【机器学习】卷积和反向传播

一、说明 自从 AlexNet 在 2012 年赢得 ImageNet 竞赛以来&#xff0c;卷积神经网络 (CNN) 就变得无处不在。从不起眼的 LeNet 到 ResNets 再到 DenseNets&#xff0c;CNN 无处不在。 您是否想知道 CNN 的反向传播中会发生什么&#xff0c;特别是反向传播在 CNN 中的工作原理。…

蓝牙BLE学习-概述

1. 简介 1.1 蓝牙发展历程 蓝牙&#xff0c;直接来自于一位国王的名字--King Harald ‘Bluetooth Gromsson。这位国王因两件事留名于史&#xff0c;其一是在公园958年统一了丹麦和挪威&#xff0c;其二是在其死后&#xff0c;其牙齿呈现出暗蓝色的颜色&#xff0c;因而得名蓝牙…

WordPress修改所有用户名并发送邮件通知的插件Easy Username Updater

前面跟大家介绍了『如何修改WordPress后台管理员用户名&#xff1f;推荐2种简单方法』一文&#xff0c;但是对于有很多用户的站长来说&#xff0c;操作有点复杂&#xff0c;而且无法发邮件通知对方&#xff0c;所以今天boke112百科向大家推荐一款可以直接在WordPress后台修改所…

记录一下,我使用stm32实现pwm波输入,以及对频率和占空比的计算,同时通过串口输出(实现-重要)

1&#xff0c;首先看下半物理仿真 看下我的配置&#xff1a; 看下计算方法以及matlab的仿真输出的数据&#xff1a; timer3的ch2是选择高电平&#xff0c;计算频率 timer3的ch1是选择的是低电平&#xff0c;用来计算周期 其中TemPIpre表示的是CH2输出的值&#xff0c; TemPI…

ElasticSearch级查询Query DSL上

目录 ES高级查询Query DSL match_all 返回源数据_source 返回指定条数size 分页查询from&size 指定字段排序sort 术语级别查询 Term query术语查询 Terms Query多术语查询 exists query ids query range query范围查询 prefix query前缀查询 wildcard query通…

「计算机网络」数据链路层

数据链路层的地位&#xff1a;网络中的主机、路由器等都必须实现数据链路层信道类型 点对点信道&#xff1a;使用一对一的点对点通信方式广播信道 使用一对多的广播通信方式必须使用专用的共享信道协议来协调这些主机的数据发送 使用点对点信道的数据链路层 数据链路和帧 链…

ansible shell模块 可以用来使用shell 命令 支持管道符 shell 模块和 command 模块的区别

这里写目录标题 说明shell模块用法shell 模块和 command 模块的区别 说明 shell模块可以在远程主机上调用shell解释器运行命令&#xff0c;支持shell的各种功能&#xff0c;例如管道等 shell模块用法 ansible slave -m shell -a cat /etc/passwd | grep root # 可以使用管道…

比特币突然大涨

作者&#xff1a;秦晋 2月9日&#xff0c;除夕夜&#xff0c;比特币突然大涨&#xff0c;最高涨至48219美元&#xff0c;涨幅超6%。据CNBC报道&#xff0c;本周比特币已经上涨10.76%&#xff0c;创下自12月8日以来的最佳的一周。本周ETH上涨8.46%&#xff0c;成为自1月12日以来…

蓝桥杯-X图形

问题描述 给定一个字母矩阵。一个 X 图形由中心点和由中心点向四个 45度斜线方向引出的直线段组成&#xff0c;四条线段的长度相同&#xff0c;而且四条线段上的字母和中心点的字母相同。 一个 X 图形可以使用三个整数 r,c,L 来描述&#xff0c;其中 r,c 表示中心点位于第 r 行…

【Java程序设计】【C00261】基于Springboot的休闲娱乐代理售票系统(有论文)

基于Springboot的休闲娱乐代理售票系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的休闲娱乐代理售票系统 本系统分为系统功能模块、管理员功能模块以及用户功能模块。 系统功能模块&#xff1a;休闲娱乐代理…

视频讲解:优化柱状图

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

探索Redis特殊数据结构:Geospatial(地理位置)在实际中的应用

一、概述 Redis官方提供了多种数据类型&#xff0c;除了常见的String、Hash、List、Set、zSet之外&#xff0c;还包括Stream、Geospatial、Bitmaps、Bitfields、Probabilistic&#xff08;HyperLogLog、Bloom filter、Cuckoo filter、t-digest、Top-K、Count-min sketch、Confi…

【开源】JAVA+Vue.js实现天然气工程业务管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、使用角色3.1 施工人员3.2 管理员 四、数据库设计4.1 用户表4.2 分公司表4.3 角色表4.4 数据字典表4.5 工程项目表4.6 使用材料表4.7 使用材料领用表4.8 整体E-R图 五、系统展示六、核心代码6.1 查询工程项目6.2 工程物资…

three.js 细一万倍教程 从入门到精通(一)

目录 一、three.js开发环境搭建 1.1、使用parcel搭建开发环境 1.2、使用three.js渲染第一个场景和物体 1.3、轨道控制器查看物体 二、three.js辅助设置 2.1、添加坐标轴辅助器 2.2、设置物体移动 2.3、物体的缩放与旋转 缩放 旋转 2.4、应用requestAnimationFrame …

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之ImageAnimator组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之ImageAnimator组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、ImageAnimator组件 提供分隔器组件&#xff0c;分隔不同内容块/内容元素…

一、DataX简介

DataX简介 一、什么是DataX二、DataX设计三、支持的数据源四、框架设计五、运行原理六、DataX和Sqoop对比 一、什么是DataX DataX是阿里巴巴开源的一个异构数据源离线同步工具&#xff0c;致力于实现包括关系型数据库&#xff08;MySQL、Oracle等&#xff09;、HDFS、Hive、OD…