当前位置: 首页 > news >正文

【数据结构】基于BF算法的树种病毒检测

任务描述

双生病毒是一类世界范围内广泛存在的单链环状DNA病毒,对多种植物造成毁灭性危害。近年来,随着技术的发展,研究人员不断从苹果、桑树等多种多年生树种中检测到新的双生病毒,并将其命名为苹果双生病毒(AGV)和桑花叶萎缩相关病毒(MMDaV)。

为了快速检测出树种是否感染某种双生病毒,将树种的DNA和病毒DNA均表示成由一些字母组成的字符串序列,然后检测某种双生病毒的DNA序列是否在该树种的DNA序列中出现过,如果出现过,则此树种感染了病毒,否则没有感染。注意,树种的DNA序列是线性的,而病毒的DNA序列是环状的。

image.png

使用BF算法检测树种是否感染双生病毒,若感染,则输出“YES”,否则输出“No”。例如,双生病毒的DNA序列为baa,树种1的DNA序列为aaabbba,树种2的DNA序列为babbba,则可以判断树种1感染了双生病毒,而树种2未感染。

编程要求

输入

多组数据,每组数据有一行,为序列A和B,A对应病毒的DNA序列,B对应树木的DNA序列。A和B都为“0”时输入结束。

输出

对于每组数据输出一行,若树木感染了病毒输出“YES”,否则输出“NO”。

输入样例:

在这里给出一组输入。例如:

baa aaabbba
baa babbba
abbab abbabaab
baa aaababa
bc acbe
0 0

输出样例:

在这里给出相应的输出。例如:

YES
NO
YES
YES
YES

算法步骤:

1. 数据结构定义

使用HString结构体存储字符串,包含:

  • ch[600]:字符数组(从索引 1 开始存储,方便后续匹配逻辑);
  • len:字符串长度。

2. 核心函数功能与步骤

(1)暴力匹配算法(Index_BF
  • 作用:在主串S中从第pos个字符开始,查找模式串T第一次出现的位置。
  • 步骤:
    • 初始化主串指针i = pos(1-based)、模式串指针j = 1(1-based);
    • 若当前字符匹配(S.ch[i] == T.ch[j]),则双指针同时后移(i++j++);
    • 若不匹配,主串指针回溯到 “上次匹配起始位置 + 1”(i = i - j + 2),模式串指针重置(j = 1);
    • 若模式串遍历完毕(j > T.len),返回匹配起始位置(i - T.len);否则返回 0(无匹配)。
(2)环状序列倍增(DoubleCircularSequence
  • 作用:将环状序列(如病毒 DNA)转换为线性序列,便于提取所有旋转形式。
  • 步骤:
    • 设原序列长度为m,将原序列复制一份拼接到自身后面(如 “baa”→“baabaa”);
    • 更新序列长度为2*m,此时所有旋转形式都是该倍增序列中长度为m的子串。
(3)匹配环状模式串(MatchCircularPattern
  • 作用:检查主串(树木 DNA)中是否包含模式串(病毒 DNA)的任意旋转形式。
  • 步骤:
    • 从倍增后的病毒串中,提取所有长度为m(原病毒长度)的子串(每个子串对应一种旋转形式);
    • 对每个子串,调用Index_BF在树木 DNA 中查找;
    • 若找到任一匹配,返回匹配位置(非 0);否则返回 0。
(4)主流程(Virus_detection
  • 步骤:
    • 循环读取输入的病毒 DNA(temp1)和树木 DNA(temp2),直到输入 “0 0” 终止;
    • 将输入字符串存入HString结构(从索引 1 开始存储),并计算长度;
    • 对病毒 DNA 调用DoubleCircularSequence进行倍增处理;
    • 调用MatchCircularPattern检查树木 DNA 中是否包含病毒 DNA 的任意旋转;
    • 若存在匹配,输出 “YES”;否则输出 “NO”。

C++代码:

#include<iostream>
#include<string.h>
using namespace std;
typedef struct{   char ch[600];				//若是非空串,则按串长分配存储区,否则ch为NULL   int len;				//串长度   
}HString;
int Index_BF(HString S,HString T,int pos);
void DoubleCircularSequence(HString &str);//将环状序列倍增,便于线性处理所有旋转情况
int MatchCircularPattern(HString main, HString doubled_pattern);//在主串中查找环状模式串的所有可能旋转(假设pattern已倍增)
void Virus_detection();
int main()
{Virus_detection();return 0;
}
int Index_BF(HString S,HString T,int pos)
{//返回模式T在主串S中第pos个字符开始第一次出现的位置。若不存在,则返回值为0//其中,T非空,1≤pos≤StrLength(S)int i,j;i=pos; j=1;while(i<=S.len&&j<=T.len){if(S.ch[i]==T.ch[j]){++i;++j;}	//继续比较后继字符else{i=i-j+2;j=1;}	//指针后退重新开始匹配}if(j>T.len) return i-T.len;else return 0;
}
void DoubleCircularSequence(HString &str)
{//将环状序列倍增,便于线性处理所有旋转情况int m = str.len;int i, j;for(i=m+1, j=1; j<=m; j++)str.ch[i++] = str.ch[j];str.ch[2*m+1] = '\0';  //添加结束符号str.len = 2*m;         //更新长度为倍增后的长度
}int MatchCircularPattern(HString main, HString doubled_pattern)
{//在主串中查找环状模式串的所有可能旋转(假设pattern已倍增)int m = doubled_pattern.len / 2;  //从倍增后的长度计算原始长度int flag = 0;HString temp;// 遍历所有可能的旋转情况for(int i=0; i<m; i++){// 提取长度为m的旋转子串for(int j=1; j<=m; j++)temp.ch[j] = doubled_pattern.ch[i+j];temp.ch[m+1] = '\0';temp.len = m;  //提取的子串长度就是m// 进行模式匹配flag = Index_BF(main, temp, 1);if(flag) break;  // 找到匹配立即返回}return flag;
}
void Virus_detection()
{int flag;char temp1[600], temp2[600];  // 临时数组用于接收输入HString Virus,Tree;while(cin>>temp1>>temp2) //依次检测每对病毒DNA和树木DNA是否匹配{//判断终止条件if(strcmp(temp1,"0")==0 && strcmp(temp2,"0")==0) break;//将临时数组内容复制到HString结构(从索引1开始)strcpy(Virus.ch+1, temp1);strcpy(Tree.ch+1, temp2);Virus.len=strlen(Virus.ch+1);  //从ch[1]开始计算长度Tree.len=strlen(Tree.ch+1);//环状序列匹配处理DoubleCircularSequence(Virus);      //倍增处理flag=MatchCircularPattern(Tree,Virus); //环状序列匹配if(flag)cout<<"YES"<<endl;elsecout<<"NO"<<endl;}//while
}

Python代码:

def index_bf(S, T, pos):"""暴力匹配算法(还原C++逻辑):param S: 主串(树木DNA,0-based字符串):param T: 模式串(病毒DNA的某个旋转,0-based字符串):param pos: 匹配起始位置(1-based):return: 匹配成功返回1-based起始位置,失败返回0"""len_S = len(S)len_T = len(T)# 非法输入判断(模式串为空或起始位置越界)if len_T == 0 or pos < 1 or pos > len_S:return 0i = pos - 1  # 转换为主串0-based索引j = 0        # 模式串0-based索引while i < len_S and j < len_T:if S[i] == T[j]:i += 1j += 1else:# 回溯:主串回到上次匹配起始位置+1,模式串重置i = i - j + 1j = 0# 模式串完全匹配,返回1-based起始位置if j == len_T:return i - len_T + 1# 匹配失败return 0def double_circular_sequence(s):"""将环状序列倍增(还原C++逻辑),如"baa"→"baabaa",覆盖所有旋转情况"""return s + sdef match_circular_pattern(main_str, doubled_pattern):"""匹配环状模式串的所有旋转形式:param main_str: 主串(树木DNA):param doubled_pattern: 倍增后的模式串(病毒DNA):return: 存在匹配返回True,否则返回False"""m = len(doubled_pattern) // 2  # 病毒DNA原始长度# 遍历所有旋转情况(提取倍增串中长度为m的子串)for i in range(m):pattern = doubled_pattern[i:i+m]# 调用暴力匹配,从主串第1个字符开始if index_bf(main_str, pattern, 1) > 0:return Truereturn Falsedef virus_detection():"""主函数:读取输入并检测病毒DNA"""while True:# 读取一行输入并分割(处理可能的空行和多空格)line = input().strip()while not line:  # 跳过空行line = input().strip()temp1, temp2 = line.split()# 终止条件:两个输入均为"0"if temp1 == "0" and temp2 == "0":break# 处理病毒串和树木串virus = temp1tree = temp2# 倍增病毒串(生成所有旋转的候选子串)doubled_virus = double_circular_sequence(virus)# 检测是否存在匹配的旋转形式if match_circular_pattern(tree, doubled_virus):print("YES")else:print("NO")if __name__ == "__main__":virus_detection()

Java代码:

import java.util.Scanner;// 模拟C++中的HString结构体
class HString {char[] ch = new char[600]; // 字符数组,从索引1开始存储int len; // 串长度
}public class VirusDetection {// 暴力匹配算法:返回模式串T在主串S中从pos位置开始的第一次出现位置(1-based),不存在返回0public static int indexBF(HString S, HString T, int pos) {int i = pos; // 主串指针(1-based)int j = 1; // 模式串指针(1-based)while (i <= S.len && j <= T.len) {if (S.ch[i] == T.ch[j]) {i++;j++;} else {// 指针回溯:主串回到上次匹配起始位置+1,模式串重置i = i - j + 2;j = 1;}}if (j > T.len) {return i - T.len; // 匹配成功,返回起始位置} else {return 0; // 匹配失败}}// 将环状序列倍增(便于处理所有旋转情况)public static void doubleCircularSequence(HString str) {int m = str.len;// 将原序列复制到后面,形成倍增序列(1..m 复制到 m+1..2m)for (int i = m + 1, j = 1; j <= m; j++) {str.ch[i++] = str.ch[j];}str.ch[2 * m + 1] = '\0'; // 结束符(Java中可不显式处理,但保持逻辑一致)str.len = 2 * m; // 更新长度为倍增后的值}// 在主串中查找环状模式串的所有可能旋转(假设模式串已倍增)public static int matchCircularPattern(HString main, HString doubledPattern) {int m = doubledPattern.len / 2; // 原始模式串长度HString temp = new HString();temp.len = m;// 遍历所有可能的旋转(提取倍增串中长度为m的子串)for (int i = 0; i < m; i++) {// 构建当前旋转的模式串(从i+1位置开始取m个字符)for (int j = 1; j <= m; j++) {temp.ch[j] = doubledPattern.ch[i + j];}temp.ch[m + 1] = '\0';// 调用暴力匹配,从主串第1个字符开始查找int flag = indexBF(main, temp, 1);if (flag != 0) {return flag; // 找到匹配则返回}}return 0; // 未找到匹配}// 病毒检测主函数public static void virusDetection() {Scanner scanner = new Scanner(System.in);while (true) {String temp1 = scanner.next();String temp2 = scanner.next();// 终止条件:输入为"0 0"if (temp1.equals("0") && temp2.equals("0")) {break;}HString virus = new HString();HString tree = new HString();// 将输入字符串复制到HString(从索引1开始存储)for (int i = 0; i < temp1.length(); i++) {virus.ch[i + 1] = temp1.charAt(i);}virus.len = temp1.length();for (int i = 0; i < temp2.length(); i++) {tree.ch[i + 1] = temp2.charAt(i);}tree.len = temp2.length();// 处理环状序列并匹配doubleCircularSequence(virus);int flag = matchCircularPattern(tree, virus);// 输出结果if (flag != 0) {System.out.println("YES");} else {System.out.println("NO");}}scanner.close();}public static void main(String[] args) {virusDetection();}
}

http://www.dtcms.com/a/573148.html

相关文章:

  • 网站服务内容填网站建设可以网站友链查询源码
  • 详细解释 半正定性:对任意非零向量 v,有 vTΣv≥0。
  • 智能家居系统设计与实施方案
  • 【算法】图相关算法和递归
  • Vue开发系列——读取本地资源报错‘Not allowed to load local resource:
  • 【Java基础14】函数式接口、lamba表达式、方法引用一网打尽(下)
  • 金仓KES vs. 达梦DM:全面对比解析迁移、运维与授权成本
  • 国际网站如何推做推广个人做百度云下载网站吗
  • 【Python爬虫基础-1】爬虫开发基础
  • 外贸设计网站邯郸微信托管
  • 深度学习_原理和进阶_PyTorch入门(1)
  • C# 实现在 Excel 中高效生成和操作表格
  • OpenTeleDB xstore vs GaussDB ustore表膨胀测试
  • 使用 OpenAI Responses API 构建生产级应用的终极指南—— 状态、流式、异步与文件处理
  • 2025/11/5 IO流(字节流、字符流、字节缓冲流、字符缓冲流) 计算机存储规则(ASCII、GBK、Unicode)
  • 解决excel复制页面行高无法复制的问题
  • SSO登录验证设计要点细节(以微软 Microsoft SSO为例) 基于react python
  • 郑州网站备案地址移动互联网开发工程师证书
  • 网站建设的难处wordpress 臃肿
  • 芯谷科技--D29152高性能低降压可调稳压器,驱动高效电源管理新体验
  • 代码随想录第59天 | 最短路算法:dijkstra和Bellman_ford
  • web自动化测试详解
  • 网站建设文章官网小程序定制开发中心
  • PortSwigger靶场之利用开放重定向漏洞绕过过滤器的 SSRF 攻击通关秘籍
  • 深入理解 Spring 原理:IOC、AOP 与事务管理
  • 做网站公司赚钱吗怎么怎么做网站
  • 使用ESP8266+SG90舵机实现物理远程开机
  • 第四阶段C#通讯开发-5:TCP
  • WABT 项目全解析:WebAssembly 二进制工具套件
  • 第四阶段C#通讯开发-5:Socket与RS485 / Modbus联调