奇怪的比赛(Python,递归,状态压缩动态规划dp)

目录

  • 前言:
  • 题目:
  • 思路:
    • 递归:
      • 代码及详细注释:
    • 状态压缩dp:
      • 代码及详细注释:
  • 总结:

前言:

这道题原本是蓝桥上的题,现在搜不到了,网上关于此题的讲解更是寥寥无几,仅有的讲解也只是递归思想,python讲解和状态压缩dp的解决方法都没有,这里就带大家用状态压缩dp方法来解决此题。

题目:

大奖赛计分规则:
每位选手需要回答10个问题(其编号为1到10),越后面越有难度。答对的,当前分数翻倍;答错了,则扣掉与题号相同的分数(选手必须回答问题,不回答按错误处理)。每位选手的起步分都是10分,某获胜选手最终得分刚好是100分,请推断出哪个题目答对了,哪个题目答错了?(答对的记为1,答错的记为0,则10个题目的回答情况可用仅含1和0的串来表示)。任务是算出所有可能情况,每个答案占一行。(填空题)

输出:
0010110011
0111010000
1011010000

思路:

递归:

分析本题首先想到递归思想,从得分100逆推出初始分数为10的方案。
首先定义一个字符串

如果本题答对了,则总得分除2,字符串首位加1(因为是从第10题往前推,所以要逆序加)

如果本题答错了,则总得分加上本题的序号数,字符串首位加0

这里还有一个小细节,如果得分是奇数,则不能除2(只能答错)。

代码及详细注释:

def ScoreOut(qs, score, out):
    # 如果qs为0
    if qs == 0:
        # 如果score等于10
        if score == 10:
            print(out)  # 输出当前字符串out
            return out  # 返回当前字符串out
        else:
            return ""  # 返回空字符串

    else:
        # 如果score为偶数
        if score % 2 == 0:
            # 递归调用函数,分别将score除以2并在开头添加字符"1",以及将score加上qs并在开头添加字符"O"
            return ScoreOut(qs - 1, score // 2, "1" + out) + ScoreOut(qs - 1, score + qs, "O" + out)
        else:
            # 如果score为奇数,只递归调用将score加上qs并在开头添加字符"O"
            return ScoreOut(qs - 1, score + qs, "O" + out)

# 初始调用函数
ScoreOut(10, 100, "")

状态压缩dp:

什么是状态压缩

利用一串0/1数字(二进制数)来表示各个点的状态

这就要求使用状态压缩的对象的状态必须只有两种,0 或 1(如果有三种状态用三进制来表示也未尝不可)。

需要将状态数据实现为基本数据类型,比如 int,long 等,即状态压缩。比如说棋盘上的格子,放棋子或者不放;硬币的正面或反面;题目的对或错等。

状态压缩要求状态数据中的单元个数不能太大,比如用 int 来表示一个状态的时候,状态的单元个数不能超过 32(32位CPU),所以题目一般都是至少有一维的数据范围很小。

当然Python不需要考虑数的大小是否受限。

分析本题,上面用递归讲解过本题,有递归就用动态规划来解决,众所周知,递归很好理解和书写,但是递归的时间复杂度都不低,会有大量冗余计算。像本题中

如图

在这里插入图片描述
会出现大量相同得分情况,这就需要借助动态规划来处理重复计算了。

动态规划五部曲来分析

  1. 确定dp数组的定义

对于数组dp[i] :

下标表示10道题目的对错状态,dp[i]表示对应得分

下标 i 的二进制数表示对错状态,如 i = 2 时 i 的二进制数为 10 ,此时10(第1题答错,之后的提还没有做)(二进制数)的得分为多少,i = 7 时,i的二进制数为111,此时(第1题答对,第2题答对,之后的题还没有做)的得分为多少
特别注意!!! 这里首位的1(二进制后的数)没有实际含义,不表示题目对错,这个在下面会讲解

题目中有10道题,总共的有2 ** 10 - 1 种可能种情况(可能的情况用2进制计算就可以得出,如从000000000到111111111的可能数)

对于0000000000(这些都是10个数,不用挨个数了),二进制是这么表示,但10进制中,这个数就是0,

要想这个二进制数有意义,最前面就要加个1,否则无论有几个0,都表示0这个数,所以我们在定义dp数组长度的时候,不能为2 ** 10 而是为 2 ** 11(因为二进制1000000000(1后面10个0)的10进制数为 2 ** 11)

大家之前做题接触的二进制情况肯定不多,所以这里会稍微有点绕。这里主要理解前面自定义的1就好,跟补码的符号位有异曲同工之妙,只不过这里仅仅用来补位。

  1. dp数组的递推公式

状态压缩dp的递推公式还跟别的动规的递推公式不太一样,这里需要用到位运算符

这里简单讲解一下位运算符:

<< : 表示运算数的各二进制位全部左移若干位,低位补0
7 << 1 = 14, 因为7的二进制数为111,左移一位后为1110,1110的十进制数为14

右移跟左移同理。

还有python的二进制数可以用bin()函数来求,如bin(7) = 0b111,0b表示二进制,bin(7)的类型为字符串型。但是直接写0b111 就表示整型

因为第二道题的得分是由第一道题的得分算出来的,如

dp[0b1 << 1] = dp[0b1] - 1          #   dp[0b10]即dp[2]
dp[(0b1 << 1) +1] = dp[0b1] * 2      #  dp[0b11]即dp[3]

对于第cur道题,

如果答错dp[i << 1] = dp[i] - cur
如果答对dp[(i << 1) + 1] = dp[i] * 2

在推导递推公式的时候如果不太清楚,就看看dp数组的定义,切记第一个1无实义

  1. dp数组如何初始化

因为第一个1无实义,所以

dp[0b1] = 10  # dp[1]初始化得分为10
  1. dp数组遍历顺序

毫无疑问,题是从前往后答的,dp数组也是从左往右推

  1. 打印dp数组

画的有点丑,下标最好写成二进制形式。
在这里插入图片描述

求出dp数组后就把得分为100且10道题全都做了的结果输出就行。比较简单,有很多种方法,就不细说了。

代码及详细注释:

import math

# 初始化一个长度为2^11的数组,初始值为0
dp = [0] * 2 ** 11
dp[1] = 10  # dp[1]初始化得分为10
# dp[0b1 <<1] = dp[0b1] - 1             dp[0b10]即dp[2]
# dp[(0b1 <<1) +1] = dp[0b1] * 2        dp[0b11]即dp[3]

maxscore = 160  # 最大分数为160(因为160怎么减题目序号都到不了100,也可以设170等等)
for i in range(1, 2 ** 10):
    if dp[i] == -1:
        continue
    else:
        cur = int(math.log2(i << 1))  # 计算准备做的题目序号,因为第一个1无实际意义,1之后的数才表示题的对错
        if dp[i] - cur <= 0:
            dp[i << 1] = -1
        else:
            dp[i << 1] = dp[i] - cur
        if dp[i] * 2 >= maxscore:
            dp[(i << 1) + 1] = -1
        else:
            dp[(i << 1) + 1] = dp[i] * 2

result = []
while True:
    if 100 in dp:
        index = dp.index(100)  # 找到值为100的索引
        dp[index] = 0
        if len(bin(index)) == 13:
            result.append(bin(index))  # 将长度为13(10道题都做完了,头三位为0b1)的二进制数添加到结果列表中
    else:
        break

for res in result:
    print(res[3:])  # 输出结果列表中每个元素的第3位之后的内容

总结:

状态压缩dp还是比较难的,但把dp的定义吃透就比较好理解了。

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

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

相关文章

【SQL】1280. 学生们参加各科测试的次数 (笛卡尔积)

前述 知识点回顾&#xff1a;数据库中的四大join & 笛卡尔乘积&#xff08;以MySQL为例&#xff09; 笛卡尔积的两种写法 select * from stu,class; select * from stu cross join class; 题目描述 leetcode题目&#xff1a;1280. 学生们参加各科测试的次数 Code 写法…

【算法与数据结构】堆排序TOP-K问题

文章目录 &#x1f4dd;堆排序&#x1f320; TOP-K问题&#x1f320;造数据&#x1f309;topk找最大 &#x1f6a9;总结 &#x1f4dd;堆排序 堆排序即利用堆的思想来进行排序&#xff0c;总共分为两个步骤&#xff1a; 建堆 升序&#xff1a;建大堆 降序&#xff1a;建小堆利…

SpringBoot项目通过触发器调度实现定时任务

文章目录 前言一、quartz是什么&#xff1f;二、quartz中核心概念三、集成步骤1.引入依赖2.demo样例a.定义一个任务参数实体类b.定义操作触发器、定时任务接口及实现c.作业实现d.结果截图 四、其他1.QuartzJobBean和Job区别2.注意事项3.作业&#xff08;Job&#xff09;和触发器…

2024年跨境电商大热门:哪个平台最具赚钱潜力?!

2024年&#xff0c;哪个跨境电商平台好做&#xff0c;这取决于多种因素&#xff0c;如平台的知名度、流量、用户基础、市场定位、费用结构以及个人或企业的具体需求和资源。以下是一些近期比较热门&#xff0c;表现突出的跨境电商平台&#xff0c;但请注意&#xff0c;每个平台…

数据库系统概论(超详解!!!) 第四节 关系数据库标准语言SQL(Ⅰ)

1.SQL概述 SQL&#xff08;Structured Query Language&#xff09;结构化查询语言&#xff0c;是关系数据库的标准语言 SQL是一个通用的、功能极强的关系数据库语言 SQL的动词 基本概念 基本表 &#xff1a;本身独立存在的表&#xff1b; SQL中一个关系就对应一个基本表&am…

分享最有效脱单方法【单身狗必看】

用这个方法找不到对象我倒立 ! 发送内容: "脱单神器", 实现今年脱单

# termux连接云服务器

连接服务器 ssh nameip termux使用 pkg install openssh

Java Swing游戏开发学习14

内容来自RyiSnow视频讲解 前言 这一节讲的是Custom Font定制字体&#xff0c;就是在游戏中显示文字的地方&#xff0c;使用特定的ttf字体文件进行文字显示&#xff0c;提升游戏体验。如果觉得arial字体可以接受&#xff0c;这一节可以跳过&#xff0c;或者认为它太普通&#…

Linux离线安装Docker-Oracle_11g

拉取oracle11g镜像 docker pull registry.cn-hangzhou.aliyuncs.com/helowin/oracle_11g创建11g容器 docker run -d -p 1521:1521 --name oracle11g registry.cn-hangzhou.aliyuncs.com/helowin/oracle_11g查看容器是否创建成功 docker ps -a导出oracle容器&#xff0c;查看…

HarmonyOS入门学习

HarmonyOS入门学习 前言快速入门ArkTS组件基础组件Image组件Text组件TextInput 文本输入框Buttonslider 滑动组件 页面布局循环控制ForEach循环创建组件 List自定义组件创建自定义组件Builder 自定义函数 状态管理Prop和LinkProvide和ConsumeObjectLink和Observed ArkUI页面路由…

MCU技术的创新浪潮与产业变革

MCU技术的创新浪潮与产业变革 一、MCU技术的创新发展 MCU&#xff0c;即微控制器&#xff0c;作为现代电子设备的核心部件&#xff0c;一直在不断地创新与发展。随着科技的进步&#xff0c;MCU的性能得到了极大的提升&#xff0c;功能也越来越丰富。从8位到32位&#xff0c;再…

OpenCV4.9.0在Android 开发简介

查看&#xff1a;OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇&#xff1a;使用 Clojure 进行 OpenCV 开发简介 下一篇&#xff1a;暂无 引言&#xff1a; OpenCV是一个跨平台计算机视觉库&#xff0c;广泛用于图像处理、计算机视觉和机器学习等领域…

TinyEMU源码分析之虚拟机初始化

TinyEMU源码分析之虚拟机初始化 1 初始化结构参数2 配置RAM地址空间3 初始化设备4 拷贝BIOS和Kernel5 手动写入5条指令6 体验第一条指令的执行 本文属于《 TinyEMU模拟器基础系列教程》之一&#xff0c;欢迎查看其它文章。 本文中使用的代码&#xff0c;均为伪代码&#xff0c…

Java 面向对象编程进阶七(字符串 String )

目录 字符串 String String 基础 String 类和常量池 String 类常用的方法 String 类常用方法一 String 类常用方法二 字符串相等的判断 字符串 String String 是我们开发中最常用的类&#xff0c;我们不仅要掌握 String 类常见的方法&#xff0c;对于 String 的 底层实现…

Vue.js+SpringBoot开发智能教学资源库系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 课程档案模块2.3 课程资源模块2.4 课程作业模块2.5 课程评价模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 课程档案表3.2.2 课程资源表3.2.3 课程作业表3.2.4 课程评价表 四、系统展示五、核心代…

多进程数据库不适合作为hive的元数据库

简介 “今天发现一个比较奇怪的现象&#xff0c;因为博主不熟悉mysql&#xff0c;所以在安装hive的使用了postgresql作为hive的元数据库&#xff0c;在测试几个连接工具对hive进行链接&#xff0c;后面再测试的时候发现链接不上了&#xff0c;并且报错日志如下&#xff1a;” …

【记录39】html element-ui 加载

环境 html使用element-ui组件、用vue框架搭建 方法一&#xff1a; 方法二&#xff08;推荐&#xff09; 将相关资源下载下来&#xff0c;在对应的html文件中相对路径引入。注意&#xff1a;css加载放在js之前

导航栏还是侧栏?flutter 跨平台适配指南

介绍 引言&#xff1a;Flutter 的跨平台特性 Flutter 是由 Google 开发的一款跨平台应用开发框架&#xff0c;它具有许多优点&#xff0c;包括性能优异、开发效率高以及良好的用户体验等。其中&#xff0c;最引人注目的特性之一就是其出色的跨平台能力。通过编写一套代码&…

数学建模(熵权法 python代码 例子)

目录 介绍&#xff1a; 模板&#xff1a; 例子&#xff1a;择偶 极小型指标转化为极大型&#xff08;正向化&#xff09;&#xff1a; 中间型指标转为极大型&#xff08;正向化&#xff09;&#xff1a; 区间型指标转为极大型&#xff08;正向化&#xff09;&#xff1a…

电脑设备管理器在哪?这里有详细指南!

电脑设备管理器是Windows操作系统中一个重要的工具&#xff0c;它允许用户查看和管理计算机中的硬件设备。无论是查找设备驱动程序、识别硬件问题还是管理设备属性&#xff0c;设备管理器都是一个不可或缺的工具。在本文中&#xff0c;我们将介绍三种常见的方法&#xff0c;以分…