基于Bert+Attention+LSTM智能校园知识图谱问答推荐系统——NLP自然语言处理算法应用(含Python全部工程源码及训练模型)+数据集

news2024/12/26 22:27:08

目录

  • 前言
  • 总体设计
    • 系统整体结构图
    • 系统流程图
  • 运行环境
    • Python 环境
    • 服务器环境
  • 模块实现
    • 1. 构造数据集
    • 2. 识别网络
    • 3. 命名实体纠错
    • 4. 检索问题类别
    • 5. 查询结果
  • 系统测试
    • 1. 命名实体识别网络测试
    • 2. 知识图谱问答系统整体测试
  • 工程源代码下载
  • 其它资料下载


在这里插入图片描述

前言

这个项目充分利用了Google的Bert模型,这是一种基于Attention的大规模语料预训练模型,以及LSTM命名实体识别网络。项目的目标是设计一套通用的问答系统处理逻辑,以实现智能问答任务。

首先,我们采用了Bert模型,这是一种在自然语言处理领域非常强大的预训练模型。它具备对上下文的深刻理解和信息抽取能力,有助于理解复杂的自然语言问题。

接着,我们构建了一个LSTM命名实体识别网络。这个网络可以识别文本中的命名实体,例如人名、地名、组织机构等。这对于问答系统的准确性非常重要,因为它有助于识别问题中提到的实体,并提供相关信息。

在项目的设计中,我们着重考虑了通用的处理逻辑,使得问答系统能够适应各种不同领域和主题的问题。这个通用逻辑包括问题解析、文本理解、命名实体识别、答案生成等步骤。

最终,我们成功地实现了一个智能问答系统,它可以接受用户提出的问题,并基于Bert模型和LSTM命名实体识别网络,理解问题并提供精确的答案。这个系统的通用性使得它在多个领域和应用中都具有广泛的潜力,从解答常见问题到处理专业领域的知识查询。

总体设计

本部分包括系统整体结构图和系统流程图。

系统整体结构图

系统整体结构如图所示。

在这里插入图片描述

系统流程图

系统流程如图所示。

在这里插入图片描述
Neo4j数据库流程如图所示。

在这里插入图片描述

运行环境

本部分包括 Python 环境和服务器环境。

Python 环境

需要Python 3.7及以上配置,在Windows环境下载Anaconda完成Python所需的配置,下载地址为https://www.anaconda.com/,也可下载虚拟机在Linux环境下运行代码。TensorFlow 1.0, NumPy, py-Levenshtein, jieba, Scikit-learn 依据根目录文件requirement.txt下载。

pip install -r requirement.txt -i https://pypi.tuna.tsinghua.edu.cn/simple 

服务器环境

Mac/Windows 10用户可直接从终端通过SSH (Secure Shell)访问服务器。Windows 7用户可安装OpenSSH访问。

OpenSSH是SSH协议的免费开源实现,可以进行远程控制,或在计算机之间传送文件。实现此功能的传统方式,会使用明文传送密码。缺点:Telnet(终端仿真协议)、RCP、FTP、 Login、 RSH不安全。

OpenSSH提供了服务器端后台程序和客户端工具,用来加密远程控制和文件传输过程中的数据,并由此代替原来的类似服务。下 载地址为https://www.mls-software.com/opensshd.html,下载后按照默认完成安装即可。打开cmd命令窗口即可远程操作,如图所示。

在这里插入图片描述

模块实现

本项目包括5个模块:构造数据集、识别网络、命名实体纠错、检索问题类别、查询结果,下面分别给出各模块的功能介绍及相关代码。

1. 构造数据集

数据是从北京邮电大学图书馆网站爬取,主要包含教师的电话、研究方向、性别,以及课程的学分、开设学期等信息。通过循环语句按照中文习惯将爬取的信息构造为问句的形式,并对构造的语句进行标注,无用实体标记为0,将有用实体分为三类: TEA (老师)、COU (课程)、DIR (研究方向)。标注方式为实体开头B——实体类别标注,非实体开头为I——实体类别标注,训练集数据如图所示。
在这里插入图片描述
加载训练集相关代码如下:

def _read_data(cls, input_file):
    #读取数据集文件
    with codecs.open(input_file,'r',encoding='utf-8') as f:
        lines = []
        words = []
        labels = []
        for line in f:
            contends = line.strip()
            tokens = contends.split('\t')
            if len(tokens) == 2:
                words.append(tokens[0])
                labels.append(tokens[1])
            else:
                if len(contends) == 0:
                    l=''.join([label for label in labels if len(label) > 0])
                    w = ' '.join([word for word in words if len(word) > 0])
                    lines.append([l, w])
                    words = []
                    labels = []
                    continue
            if contends.startswith("-DOCSTART-"):
                words.append('')
                continue
        return lines
#读取训练集
def get_train_examples(self, data_dir):
    return self._create_example(
        self._read_data(os.path.join(data_dir, "train.txt")), "train"
    )
#读取验证集
def get_dev_examples(self, data_dir):
    return self._create_example(
    self._read_data(os.path.join(data_dir,"dev.txt")),"dev"
    )
#读取测试集
def get_test_examples(self, data_dir):
    return self._create_example(
        self._read_data(os.path.join(data_dir, "test.txt")), "test")

2. 识别网络

使用Google的Bert,调用LSTM模型代码,加以修改,进行训练。

def train_ner():  #定义训练
    import os
    from bert_base.train.train_helper import get_args_parser
    from bert_base.train.bert_lstm_ner import train
    args = get_args_parser()
    if True:
        import sys
        param_str = '\n'.join(['%20s = %s' % (k, v) for k, v in sorted(vars(args).items())])
        print('usage: %s\n%20s   %s\n%s\n%s\n' % (' '.join(sys.argv), 'ARG', 'VALUE', '_' * 50, param_str))
    print(args)
    os.environ['CUDA_VISIBLE_DEVICES'] = args.device_map
    train(args=args)
#数据处理代码
def convert_single_example(ex_index, example, label_list, max_seq_length, tokenizer, output_dir, mode):
#将一个样本进行分析,字和标签转化为ID,结构化到输入特征对象中
    label_map = {}
    #1表示从1开始对标签进行索引化
    for (i, label) in enumerate(label_list, 1):
        label_map[label] = i
    #保存label->index 的映射
    if not os.path.exists(os.path.join(output_dir, 'label2id.pkl')):
        with codecs.open(os.path.join(output_dir,'label2id.pkl'),'wb')as w:
            pickle.dump(label_map, w)
    textlist = example.text.split(' ')
    labellist = example.label.split(' ')
    tokens = []
    labels = []
    for i, word in enumerate(textlist):
    #分词,不在BERT的vocab.txt中,则进行WordPiece处理,分字可替换为list(input)
        token = tokenizer.tokenize(word)
        tokens.extend(token)
        label_1 = labellist[i]
        for m in range(len(token)):
            if m == 0:
                labels.append(label_1)
            else:  #一般不会出现else分支
                labels.append("X")
    #tokens = tokenizer.tokenize(example.text)
    #序列截断
    if len(tokens) >= max_seq_length - 1:
        tokens = tokens[0:(max_seq_length - 2)]  
#-2的原因是因为序列需要加一个句首和句尾标志
        labels = labels[0:(max_seq_length - 2)]
    ntokens = []
    segment_ids = []
    label_ids = []
    ntokens.append("[CLS]")  #句子开始设置CLS标志
    segment_ids.append(0)
    #append("O") or append("[CLS]") not sure!
    label_ids.append(label_map["[CLS]"])  
#O或者CLS会减少标签个数,但句首和句尾使用不同的标志标注
    for i, token in enumerate(tokens):
        ntokens.append(token)
        segment_ids.append(0)
        label_ids.append(label_map[labels[i]])
    ntokens.append("[SEP]")  #句尾添加[SEP]标志
    segment_ids.append(0)
    #append("O") or append("[SEP]") not sure!
    label_ids.append(label_map["[SEP]"])
    input_ids = tokenizer.convert_tokens_to_ids(ntokens)  
#将序列中的字(ntokens)转化为ID形式
    input_mask = [1] * len(input_ids)
    #label_mask = [1] * len(input_ids)
    #使用padding 
    while len(input_ids) < max_seq_length:
        input_ids.append(0)
        input_mask.append(0)
        segment_ids.append(0)
        label_ids.append(0)
        ntokens.append("**NULL**")
        #label_mask.append(0)
    #print(len(input_ids))
    assert len(input_ids) == max_seq_length
    assert len(input_mask) == max_seq_length
    assert len(segment_ids) == max_seq_length
    assert len(label_ids) == max_seq_length
    #assert len(label_mask) == max_seq_length
    #打印部分样本数据信息
    if ex_index < 5:
        tf.logging.info("*** Example ***")
        tf.logging.info("guid: %s" % (example.guid))
        tf.logging.info("tokens: %s" % " ".join(
            [tokenization.printable_text(x) for x in tokens]))
        tf.logging.info("input_ids:%s"% " ".join([str(x) for x in input_ids]))
        tf.logging.info("input_mask: %s" % " ".join([str(x) for x in input_mask]))
        tf.logging.info("segment_ids: %s" % " ".join([str(x) for x in segment_ids]))
        tf.logging.info("label_ids: %s" % " ".join([str(x) for x in label_ids]))
        # tf.logging.info("label_mask: %s" % " ".join([str(x) for x in label_mask]))
    #结构化为一个类
    feature = InputFeatures(
        input_ids=input_ids,
        input_mask=input_mask,
        segment_ids=segment_ids,
        label_ids=label_ids,
        #label_mask = label_mask
    )
    #mode='test'的时候才有效
    write_tokens(ntokens, output_dir, mode)
    return feature

3. 命名实体纠错

对识别到的课程实体进行纠错,依据为course.txt中存储的所有课程全称,采用最短编辑距离匹配法与包含法相结合。

class Select_course:
    def __init__(self):
        self.f = csv.reader(open('QA/dict/course.txt','r'))
        self.course_name = [i[0].strip() for i in self.f]
        self.led = 3
        self.limit_num = 10
        self.select_word = []
        self.is_same = False
        self.have_same_length = False
        self.input_word = ''
        self.is_include = False
        #print(self.course_name)
        #print('列表创建完毕....')
    #包含搜索
    def select_first(self, input_word):
        self.select_word = []
        self.is_same = False
        self.is_include = False
        self.have_same_length = False
        self.input_word = input_word
        if input_word in self.course_name:
            self.is_same = True
            self.select_word.append(input_word)
                if self.is_same == False:
            for i in self.course_name:
                mark = True
                for one_word in input_word:
                    if not one_word in i:
                        mark = False
                if mark:
                    self.select_word.append(i)
            if len(self.select_word) != 0:
                self.is_include = True
        #print('第一轮筛选:')
        #print(self.select_word)
    #模糊搜索
    def select_second(self):
        self.led = 3
        if self.is_same or self.is_include:
            return
        for name in self.course_name:
                ed = ls.distance(self.input_word, name)
                if ed <= self.led:
                    self.led = ed
                    self.select_word.append(name)
        select_word_copy1 = copy.deepcopy(self.select_word)
        for name in select_word_copy1:
            ed = ls.distance(self.input_word, name)
            if ed > self.led:
                self.select_word.remove(name)
            if ed == self.led and len(name) == len(self.input_word):
                self.hava_same_length = True
        #print('第二轮筛选:')
        #print(self.select_word)

对识别到的老师实体进行纠错,依据为teacher.csv中存储的所有老师姓名全称,基于最短编辑距离匹配法,并使纠错逻辑符合用户输入错误姓名的规律。

class Select_name:
    def __init__(self):  #定义初始化
        self.f = csv.reader(open('QA/dict/teacher.csv','r'))
        self.teacher_name = [i[0] for i in self.f]
        self.led = 3
        self.limit_num = 10
        self.select_word = []
        self.have_same_length = False
        self.is_same = False
        self.input_word = ''
        #print(self.teacher_name)
        #print('列表创建完毕....')
    def select_first(self, input_word):  #定义首选
        self.select_word = []
        self.have_same_length = False
        self.is_same = False
        self.input_word = input_word
        if input_word in self.teacher_name:
            self.is_same = True
            self.select_word.append(input_word)
                if self.is_same == False:
            for name in self.teacher_name:
                ed = ls.distance(self.input_word, name)
                if ed <= self.led:
                    self.led = ed
                    self.select_word.append(name)
                    select_word_copy1 = copy.deepcopy(self.select_word)
            for name in select_word_copy1:
                ed = ls.distance(self.input_word, name)
                if ed > self.led:
                    self.select_word.remove(name)
                if ed == self.led and len(name) == len(self.input_word):
                    self.hava_same_length = True
        #print('第一轮筛选:')
        #print(self.select_word)
        return
        def select_second3(self):  #定义后续筛选
        if self.is_same == True or len(self.input_word) != 3:
            return 
        select_word_copy2 = copy.deepcopy(self.select_word)
        if self.hava_same_length:
            for name in select_word_copy2:
                if len(self.input_word)!=len(name):
                    self.select_word.remove(name)
        #print('第二轮筛选:')
        #print(self.select_word)
        def select_third3(self):
        if self.is_same == True or len(self.input_word) != 3:
            return 
        select_word_copy3 = copy.deepcopy(self.select_word)
        self.select_word = []
        for name in select_word_copy3:
            if name[0] == self.input_word[0] and name[2] == self.input_word[2]:
                self.select_word.append(name)
        for name in select_word_copy3:
          if not(name[0]==self.input_word[0]and name[2]== self.input_word[2]):
                self.select_word.append(name)
        #print('第三轮筛选:')
        #print(self.select_word)
    def limit_name_num(self):
        while(len(self.select_word)>self.limit_num):
            self.select_word.pop()
        #print('列表大小限制:')
        #print(self.select_word)

4. 检索问题类别

以下为三个类别的关键词列表:

self.direction_qwds= [“ 做什么”“干什么”“专长”“专攻”“兴趣”“方向”“方面”“研究”“科研”]

self.location_qwds = [“地址”“地点”“地方”“在哪”去哪”“到哪”找到”“办公室”“位置”“见到”]

self.telephone_qwds= [“ 座机”“固话”“电话”“号码”“联系”]

通过识别到的实体类别和检索到的关键词进行问题分类,相关代码如下:

	if self.check_words(self.direction_qwds,question)and('teacher' in types):        					question_type = 'teacher_direction'  
        question_types.append(question_type)  
	if self.check_words(self.location_qwds, question)and ('teacher' in types):        question_type = 'teacher_location'  
        question_types.append(question_type)  
	if self.check_words(self.telephone_qwds,question)and ('teacher' in types):        question_type = 'teacher_telephone'  
        question_types.append(question_type)  

5. 查询结果

根据识别到的具体问题类别,将问句翻译成数据库查询语句,相关代码如下:

if final_question_type == 'teacher_direction':  
	sql = "MATCH (m:Teacher) where m.name = '{0}' return m.name, m.research_direction".format(i)  
if final_question_type == 'teacher_location':  
	sql = "MATCH (m:Teacher) where m.name = '{0}' return m.name, m.office_location".format(i)  
if final_question_type == 'teacher_telephone':  
	sql = "MATCH (m:Teacher) where m.name = '{0}' return m.name, m.telephone".format(i)  
#连接数据库
def __init__(self):  
         self.g = Graph(  
            "http://10.3.55.50:7474/browser",  
            user="********",  
            password="********")  
          self.num_limit = 30  
#查询结果并返回编写的模版答案语句
def search_main(self, sqls, final_question_types):  
         final_answers = []  
         temp_data = []  
         data = []  
         for i in sqls:  
             for one_sql in i:  
                 temp_data.append(self.g.run(one_sql).data()[0])  
                 #print(temp_data)  
             data.append(temp_data)  
             temp_data = []  
         #print(data)  
         temp_answer = []  
         answer = []  
         for i in zip(final_question_types, data):  
             for one_type_and_data in zip(i[0],i[1]):  
          temp_answer.append(self.answer_prettify(one_type_and_data[0],one_type_and_data[1]))  
             answer.append(temp_answer)  
             temp_answer = []  
         return answer  

重复询问以剔除错误的备选,例如,识别到用户输入的老师姓名为王红,但查询到北京邮电大学没有王红,存在王春红、王小红,此时重复询问用户以确定唯一实体对象。

ask_again = ''  
final_question_types = []  
for i in zip(tags, pre_words):  
	#print(i)  
	if len(i[1]) == 1:   
	    final_question_types.append(classifier.classify(text, i[0]))  
	    final_words.append(i[1][0])  
	 if len(i[1]) > 1:  
	    print('>1')  
	    if i[0] == 'teacher':  
	        ask_again = '请问您要询问的是哪个老师的信息:{0}'.format(','.join(i[1]))  
	    if i[0] ==  'course':  
	        ask_again = '请问您要询问的是哪门课程的信息:{0}'.format(','.join(i[1]))  
	    #print(ask_again)  
	    answer_again = input(ask_again)  
	    final_words.append(answer_again)  
	    final_question_types.append(classifier.classify(text, i[0])) 

系统测试

本部分包括命名实体识别网络测试和知识图谱问答系统整体测试。

1. 命名实体识别网络测试

输入常用问句,从测试结果可知,测试基本能实现老师、课程实体的识别,模型训练效果如图所示。

在这里插入图片描述

2. 知识图谱问答系统整体测试

输入常用问句,从问答系统返回的答案可知,系统运行状态良好,基本能回答用户提出的问题,效果如图所示。

在这里插入图片描述

工程源代码下载

详见本人博客资源下载页


其它资料下载

如果大家想继续了解人工智能相关学习路线和知识体系,欢迎大家翻阅我的另外一篇博客《重磅 | 完备的人工智能AI 学习——基础知识学习路线,所有资料免关注免套路直接网盘下载》
这篇博客参考了Github知名开源平台,AI技术平台以及相关领域专家:Datawhale,ApacheCN,AI有道和黄海广博士等约有近100G相关资料,希望能帮助到所有小伙伴们。

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

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

相关文章

docker-compose deploy 高可用 elasticsearch TLS

文章目录 1.sysctl2. swap3. hosts4. 配置 instances.yaml5. 创建证书6. 部署7. 修改 kibanna 密码8. 清理 1.sysctl [rootgithub es_tls]# cat /etc/sysctl.conf # sysctl settings are defined through files in # /usr/lib/sysctl.d/, /run/sysctl.d/, and /etc/sysctl.d/…

第二证券:现量和现手是什么意思?

现量和现手是证券生意领域的术语。现量通常指股票或其他证券最新成交价格对应的成交量&#xff0c;而现手则是指当日生意的股票或证券的总成交量。了解这些概念关于证券生意的参与者至关重要。以下我们将从多个视点深化分析现量和现手的含义。 首要&#xff0c;现量和现手关于…

2023高教杯数学建模1:ABC题目+初步想法

2023 ABC题目初步想法 写在最前面A题&#xff1a;定日镜场的优化设计问题1&#xff1a;建模将其抽象为数学公式问题2&#xff1a;固定部分参数&#xff0c;约束条件下的局部最优化问题可尝试方法 问题3&#xff1a;约束条件下的局部最优化问题附录&#xff1a;相关计算公式参考…

Mac系统,webots和pycharm联合仿真,配置问题解决方案!

项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; 问题描述&#xff1a;mac系统下&#xff0c;webots和pycharm 联合仿真&#xff0c;适配问题 问题描述 提示&#xff1a;这里描述项目中遇到的问题&#xff1a; 换mac电脑了&#xff0c;需要用到web…

4K超高清飞行箱(EFP)制作系统

EFP&#xff08;Electronic Field Production&#xff09;是一种节目现场制作方式&#xff0c;它将音视频设备集成在不同规格的标准飞行箱内&#xff0c;并将其运送至现场进行节目制作。与电视台演播室和大型转播车相比&#xff0c;箱载EFP系统具有操作方便、灵活部署、便携运输…

SpringMvc--CRUD

目录 一.什么是SpringMvc--CRUD 二.前期准备 公共页面跳转(专门用来处理页面跳转) 三.ssm之CRUD后端实现 配置pom.xml 双击mybatis-generator:generate自动生成mapper 编写generatorConfig.xml 项目结构 编写PagerAspect切面类 编写hpjyBiz接口类 编写hpjyBizImpl接…

如何使用Docker部署debezium来监控 MySQL 数据库

目录 一、什么是Docker 二、什么是debezium 三、什么是MySQL 四、如何使用Docker部署debezium来监控 MySQL 数据库 一、什么是Docker Docker是一个开源的应用容器引擎&#xff0c;它让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中&#xff0c;然后发布到任何流…

扫地僧万能HTML模板站群:打造高效便捷的网站建设利器

扫地僧万能HTML模板站群是一款功能强大的网站建设工具&#xff0c;以其独特的特点和卓越的性能在网络开发领域广受赞誉。本文将介绍扫地僧万能HTML模板站群的几大特点&#xff0c;包括模板自动处理、一站管理、泛站独立、多套模板、蜘蛛统计、超强自定义、超强负载、简单高效、…

sql server 分区表

分区表 分区表是在SQL Server 2005之后的版本引入的特性&#xff0c;这个特性允许把逻辑上的一个表在物理上分为很多部分。换句话说&#xff0c;分区表从物理上看是将一个大表分成几个小表&#xff0c;但是从逻辑上看&#xff0c;还是一个大表。 步骤 创建分表区的步骤分为…

初学Python记

Python这个编程语言的大名当然听说过了呀&#xff0c;这几年特别火&#xff0c;火的一塌涂地。大家可以回忆一下&#xff1a;朋友圈推荐的广告里经常可以看见python的网课广告。 本学期&#xff0c;学校开设了python课程&#xff0c;这几天学习了一下入了一下门&#xff0c;感…

扫地僧站群·静态养站王:自动万站智能LOGO功能说明

扫地僧站群静态养站王:自动万站智能LOGO功能说明,无需配置,自动根据网站状态生成对应LOGO&#xff0c;高质量LOGO万站不重样.说明&#xff1a;模板调用智能LOGO方式&#xff1a;{当前域名}/logo.png 自动识别HTTP/HTTPS 只需在模板需要展示LOGO的地方放上如上标签即可。以下为L…

OpenCV 05(图像的算术与位运算)

一、图像的算术运算 1.1 图像的加法运算 - add opencv使用add来执行图像的加法运算 图片就是矩阵, 图片的加法运算就是矩阵的加法运算, 这就要求加法运算的两张图shape必须是相同的. import cv2 import numpy as npcat cv2.imread(D:\\3-project\\zyj\\pythonCNN\\pic\\c…

为什么需要 TIME_WAIT 状态

还是用一下上一篇文章画的图 TCP 的 11 个状态&#xff0c;每一个状态都缺一不可&#xff0c;自然 TIME_WAIT 状态被赋予的意义也是相当重要&#xff0c;咱们直接结论先行 上文我们提到 tcp 中&#xff0c;主动关闭的一边会进入 TIME_WAIT 状态&#xff0c; 另外 Tcp 中的有 …

Vue之scope属性

简介&#xff1a; 在使用Vue脚手架进行开发时&#xff0c;cli编译的时候本质上处理的是一个个文本文件&#xff0c;也就是字符串。每一个组件&#xff0c;即.Vue文件都是一个文本文件&#xff0c;里面包含着模板、组件对象实例以及style样式。组件化开发时&#xff0c;难免会出…

基本导数公式、两个重要极限、x趋于0的等价替换

自然界中&#xff0c;几乎一切事物都可以用函数来描述。我们生活在一个动态变化的世界&#xff0c;对函数求导&#xff0c;可以看出变量之间的变化规律。研究函数与导数有着重要意义&#xff0c;导数可以用于求解函数的极值问题、速度和加速度、切线、法线和曲率等问题&#xf…

LeetCode(力扣)46. 全排列Python

LeetCode46. 全排列 题目链接代码 题目链接 https://leetcode.cn/problems/permutations/ 代码 class Solution:def backtracking(self, nums, result, path, used):if len(path) len(nums):result.append(path[:])for i in range(len(nums)):if used[i]:continuepath.app…

优化VUE Element UI的上传插件

默认ElmentUI的文件列表只有一个删除按钮&#xff0c;我需要加预览、下载、编辑等&#xff0c;就需要优化显示结果。 优化后没用上传进度条&#xff0c;又加了一个进度条效果 代码 <template><div><el-uploadclass"upload-demo"action"/"…

【二分答案 dp】 Bare Minimum Difference

分析&#xff1a; 首先我们能够得知这个优秀值具有单调性&#xff1a; 如果一个优秀值 x 1 x1 x1能够满足题目要求&#xff0c;那么任何 x ( x > x 1 ) x(x>x1) x(x>x1)显然都能符合要求 基于这一特性&#xff0c;我们想到二分答案 直接二分这个答案好像难以维护。 …

PdM和PHM有何区别?

在工业领域&#xff0c;PdM&#xff08;Predictive Maintenance&#xff0c;预测性维护&#xff09;和PHM&#xff08;Prognostics and Health Management&#xff0c;预测与健康管理&#xff09;是两个关键的术语。它们都涉及设备维护和故障预测&#xff0c;但在方法和应用方面…

洛谷 LGR SCP-J 2023 c++语言模拟试题 10. 以下程序片段的时间复杂度为( )

之前在牛客的一个群中看到有位哥们发的题 好像是洛谷哪次的模拟题&#xff0c;还写着什么 LGR SCP-J 2023 c语言模拟试题 题目 就是给段代码询问时间复杂度 for (int i1; i<n; i){for (int j1; j<n; ji){for (int k1; k<n; k j){}} } 跑代码 一开始想不出怎么解就…