POJ - 3691 DNA repair

POJ3691 DNA repair AC自动机+动态规划 Problem Address:http://poj.org/problem?id=3691 【前言】 关于这道题,我看了好几天。 刚开始确实很不好理解,不知道如何动态规划法。 不过慢慢地就看懂了。 看了很多解题报告,不过写的都不是很清楚。无奈最后终于又看了代码,才渐渐了解过来。 我觉得,很多题目都不是简单地考察一个知识点,而是多个知识点的结合。而我 阅读详情

POJ - 3691

Time Limit: 2000MS Memory Limit: 65536KB 64bit IO Format: %I64d & %I64u

Status

Description

Biologists finally invent techniques of repairing DNA that contains segments causing kinds of inherited diseases. For the sake of simplicity, a DNA is represented as a string containing characters 'A', 'G' , 'C' and 'T'. The repairing techniques are simply to change some characters to eliminate all segments causing diseases. For example, we can repair a DNA "AAGCAG" to "AGGCAC" to eliminate the initial causing disease segments "AAG", "AGC" and "CAG" by changing two characters. Note that the repaired DNA can still contain only characters 'A', 'G', 'C' and 'T'.

You are to help the biologists to repair a DNA by changing least number of characters.

Input

The input consists of multiple test cases. Each test case starts with a line containing one integers N (1 ≤ N ≤ 50), which is the number of DNA segments causing inherited diseases.
The following N lines gives N non-empty strings of length not greater than 20 containing only characters in "AGCT", which are the DNA segments causing inherited disease.
The last line of the test case is a non-empty string of length not greater than 1000 containing only characters in "AGCT", which is the DNA to be repaired.

The last test case is followed by a line containing one zeros.

Output

For each test case, print a line containing the test case number( beginning with 1) followed by the
number of characters which need to be changed. If it's impossible to repair the given DNA, print -1.

Sample Input

2
AAA
AAG
AAAG    
2
A
TG
TGAATG
4
A
G
C
T
AGT
0

Sample Output

Case 1: 1
Case 2: 4
Case 3: -1




1,建树

很明显是在字典树上的查找,但不能直接用ac自动机的字典树,因为ac自动机是通过从匹配串的每一位都搜索来避免漏掉,比如建树

            A-B-C

            B-C

当在字符串“ABCD”中查找所有字符串是,如果只从第一位开始,那么直接成功走到A-B-C上的C,但是忽略了B-C。从各个位都开始搜索一遍,就可以避免。但题目复杂度太高,并不允许这样的查找。                                   


可以这样实现,更新fail数组的同时(其实并不需要),将A-B-C上更新fail【b】时,直接将B-C连接到A-B-C的B上,即

             if (!tre[now].chi[i])

                       tr[now].ch[i]=tr[fail[now]].ch[i];

            同时flag也应该修改,将A-B-C上fail【c】连接到B-C上的C时,A-B-C中C节点的flag应该加上B-C中c的flag的值,即+1;

这样在查找时,只需要一直向下,一次就可以统计出DNA中有几个致病基因。。。


2,dp过程

因为可以修改DNA,所以字典树应该是一个完全的树,即每个父节点都有4个子节点,要么通过bfs过程连接到其他树枝,要么自身就是致病基因的一部分。

                                      a,如果下个点flag!=0 即是病毒的结尾,那么不能继续,continue即可;

                                      b,如果下个点flag=0,则可以更新,因为DNA可以随意修改,所以只有当flag!=0 是停止,否则继续

具体dp方程见代码,很明确












#include<iostream>

#include<algorithm>
#include<stdio.h>
#include<queue>
#include<string.h>
using namespace std;
char t[25],s[3000];
queue<int>q;
struct fs{int whe;int num;string str;};
queue<fs> qq;
struct node{
    int ch[5];
    void init()//清零函数
    {
        for (int w=0;w<=3;w++)
        ch[w]=0;
    }
}tr[1050];//字典树的常规构造
int T,n,ans,tot,fail[5000],flag[5000],vis[5000];
void add(char x[])
{
    int now=0;
    int len=strlen(x);
    for (int i=0;i<len;i++)
    {
        int tmp=x[i]-'0';
        if (!tr[now].ch[tmp])
        {
            tot++,tr[now].ch[tmp]=tot;
            //因为多组数据因此每新建一个点时,注意清零flag与fail及子节点
            flag[tot]=0;
            fail[tot]=0;
            vis[tot]=0;
            tr[tot].init();
        }
        now=tr[now].ch[tmp];
    }
    flag[now]++;
}
inline void bfs()
{
    for (int i=0;i<=3;i++)
    if (tr[0].ch[i]) q.push(tr[0].ch[i]);
    //首先把第一层push进去,因为第一层的fail必须是0
    //如果不在这里先push进去在下面的地方会出错
    while(!q.empty())
    {
        int now=q.front();q.pop();
        for (int i=0;i<4;i++)
        if (tr[now].ch[i])
        {
            fail[tr[now].ch[i]]=tr[fail[now]].ch[i];
            flag[tr[now].ch[i]]+=flag[tr[now].ch[i]];
            //刚才提到过的地方,可以自己脑内模拟一下
            //而且这里的构建tree树的优化,大家可以自己去阅读我提到的博客仔细思考一下,为什么不用while()循环一直找fail来查询是否存在ch[i]
            q.push(tr[now].ch[i]);
        }
        else
        tr[now].ch[i]=tr[fail[now]].ch[i];//注意这里flag的操作

       

//如果没有节点的话查找时就要查找tr[fail[now]].ch[i],那么我们就直接建一条连接两个点的边,查找时就不用再判断是否存在节点之类的问题

    }
}

int dp[2050][2050];
int main()
{
        int a=0;
        int n;

        while(1)
{
cin>>n;

        if (n==0) return 0;
        memset(vis,0,sizeof(vis));
        memset(flag,0,sizeof(flag));
        tot=0;tr[0].init();

        for (int i=1;i<=n;i++)
                {
                cin>>t;

                int len=strlen(t);
                for (int i=0;i<len;i++)
                if (t[i]=='A')
                        t[i]='0';
                else if (t[i]=='T')
                        t[i]='1';
                else if (t[i]=='G')
                        t[i]='2';
                else if (t[i]=='C')
                        t[i]='3';
                add(t);

                }
        cin>>s;
        int len=strlen(s);
         for (int i=0;i<len;i++)
                if (s[i]=='A')
                        s[i]='0';
                else if (s[i]=='T')
                        s[i]='1';
                else if (s[i]=='G')
                        s[i]='2';
                else if (s[i]=='C')
                        s[i]='3';
       // cout<<s<<endl;





        bfs();
        for (int i=0;i<=2000;i++)
                for (int j=0;j<=2000;j++)
                        dp[i][j]=9999;
                        dp[0][0]=0;
        ans=9999;
        for (int i=0;i<len;i++)
                for (int j=0;j<=tot;j++)
                        {
                        for (int k=0;k<=3;k++)
                                {
                                if (flag[tr[j].ch[k]]!=0)    continue;
                                if (s[i]==k+'0')        dp[i+1][tr[j].ch[k]]=min(dp[i+1][tr[j].ch[k]],dp[i][j]);
                                else if (s[i]!=k+'0')            dp[i+1][tr[j].ch[k]]=min(dp[i+1][tr[j].ch[k]],dp[i][j]+1);
                                }

                        }


                        for (int i=0;i<=tot;i++)
                                {
                                ans=min(ans,dp[len][i]);
                                //cout<<dp[len][i]<<endl;
                                }
                                a++;
                                cout<<"Case "<<a<<": ";

                if (ans==9999)  cout<<-1<<endl;
                else cout<<ans<<endl;
}


                                }






poj DNA排序 简单的字符串操作和求逆序对数,是程设poj习题 立即下载

相关推荐

PyTorch复现EEG-TCNet踩坑记:从BCI IV2a数据到TCN块缺失的完整解决方案

本文详细解析了使用PyTorch复现EEG-TCNet模型的全过程,重点解决了BCI IV2a数据集预处理和TCN模块缺失的技术难题。通过标准化数据流程、跨受试者验证策略以及三种因果卷积实现方案,为运动想象分类任务提供完整解决方案,帮助研究者高效实现模型复现与优化。

weixin_30699955的博客 318

poj3691--DNA repair(AC自动机+dp)

DNA repair Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 5743   Accepted: 2693 Description Biologists finally invent techniques of repairing DNA that con

随风的专栏 2362

AI应用架构师干货:智能财务分析AI平台可视化模块设计(附最佳实践)

智能财务分析的价值,从来不是“AI模型有多准”,而是“财务人员能用上AI的结果”。可视化模块的设计,本质是**“站在业务用户的角度,重新定义技术的价值”**——它不需要复杂的动画,不需要华丽的特效,只需要“把AI的结果翻译成财务人员能看懂的语言”。作为AI应用架构师,我们的使命不是“打造最先进的技术”,而是“打造最有用的技术”。而可视化,就是连接技术与业务的那座“桥”。附录:实战项目GitHub仓库(注:此处可放置实际项目的GitHub链接,包含完整代码、数据样例、部署文档)作者简介。

SuperAGI2025 1155

POJ3691.DNA repair (Trie图 && DP)

给你若干个字符串,再给你一个字符串 T ,求最少修改 T 中的多少个字符,能使 T 不包含给出的若干个字符串。 首先是多串匹配问题,所以我们自然而然地想到了 AC 自动机。然后考虑 DP:f[ i ][ j ] 表示查找第 i 个字符时在自动机上的状态为 j 的答案, 然后枚举下一次转移的字符,如果下一次转移的字符和 T 下一位要匹配的一样且不是病毒串,那么答案不变,否则答案 + 1,当

ALXPCUN的博客 774

【实战解析】Ubuntu双网卡冲突:如何解决同一网段下网关无法访问及上网问题

本文深入解析Ubuntu服务器双网卡配置在同一网段时引发的路由冲突问题,导致网关无法ping通及无法上网。通过分析路由表与Metric值原理,提供使用route命令调整优先级及修改Netplan配置文件的实战解决方案,确保主次路由明确,一劳永逸解决网络冲突。

f9g0h的博客 280

赛灵思Xilinx 7系列FPGA硬件设计知识总结

本文讲述了赛灵思7系列FPGA硬件设计的关键点,为使用该系列FPGA提供硬件设计参考。

csdn_dsw的博客 3617

POJ3691 DNA repair 题解&代码

我心好痛啊…f**k -1改成0x3f3f3f3f就过了…这么玄妙的东西我卡了半个月我服 等老师再研究一下吧,我现在不想看到这道题 //一道题的代码几乎能背过是什么体验 注释不删,等待第二版更新#include <cmath> #include <climits> #include <cstdlib> #include <iostream> #include <queue> #include

Rainbow6174's home 1018

BUPT软件安全实验三

可以看出栈溢出对程序运行的安全性有很大的威胁,如果不对栈进行保护,只要系统中存在栈溢出漏洞,即可令攻击者通过非正当方法获取操作权限。(6)解决思考题,即:在不修改StackOverrun程序源代码的情况下,构造shellcode,通过JMP ESP的方式实现通过记事本打开shellcode.txt(可使用CreateProcessA或WinExec等API)。查看缓冲区信息,可以看到dest指向地址0x0012FAF0,其为数组的存放起始位置,也就是shellcode注入的起始位置。

7xun's space 1965

poj3691 DNA repair

AC自动机上的水题DP

ACoder 525

Python实战:从中国气象局天擎平台自动化获取与处理雷达基数据

本文详细介绍了如何利用Python脚本实现从中国气象局天擎平台自动化获取与处理雷达基数据。通过环境搭建、安全认证、核心代码编写及工程化优化,构建了一个包含自动查询、批量下载、错误重试和格式转换的完整数据管道,旨在帮助气象水文领域的研究者与数据分析师从繁琐的手动操作中解放出来,高效管理海量数据。

ipfs8storage的博客 916

Sentaurus TCAD 修改字体

如题

努力学习的IC小白 5759

[poj3691] DNA repair

题目描述Biologists finally invent techniques of repairing DNA that contains segments causing kinds of inherited diseases. For the sake of simplicity, a DNA is represented as a string containing characters

Bill_Yang_2016的博客 523

STM32电机库(ST-MC-Workbench)实战指南——三电阻电流采样电路参数配置详解

本文详细解析了STM32电机库(ST-MC-Workbench)中三电阻电流采样电路的参数配置方法,涵盖电阻选型、放大增益计算、滤波时间优化等关键步骤。通过实战案例和调试技巧,帮助工程师快速掌握电流采样技术,提升电机控制系统的精度与稳定性。特别针对ST-MC-Workbench界面参数设置提供了详细指导。

weixin_29186249的博客 505

poj 3691 DNA repair

题目链接:http://poj.org/problem?id=3691 题目大意:已知一个DNA串和一些病毒DNA序列,求出最少改变DNA串中多少个字符,能使得串中不包含任意一个病毒序列。 题目思路:ac自动机加简单dp. #include #include #include #include #include #include #include #include #include #i

Wings_of_Liberty的专栏 986

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

POJ 3691 DNA repair

题意:给出n个病毒的DNA序列。同时

leodestiny 667

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

POJ 3691 DNA repair 笔记

DNA 字符串。已知N 个禁止 DNA 模式,需修改 DNA 字符串 S 。每次只能修改 S 中的一个字符,求最少修改次数。

woniupengpeng的专栏 316

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

银河麒麟V10安装QT5.12完整指南:从依赖到xcb踩坑解决

在国产化替代浪潮下,基于Linux内核的银河麒麟V10系统成为工控、能源等领域的重要平台。Qt作为跨平台C++图形界面框架,在麒麟系统上搭建Qt开发环境是许多上位机开发者的刚需。然而,由于系统依赖库策略保守,直接安装新版Qt常遭遇GLIBC或xcb平台插件加载失败等问题。选择长期支持版本QT5.12并结合系统架构(x86_64或aarch64),通过离线安装包部署,再配置QTDIR、PATH、LD_LIBRARY_PATH环境变量,并补齐libxcb、OpenGL等图形栈依赖,即可实现稳定运行。这一流程不仅

weixin_34234721的博客 397

POJ 3691 DNA repair AC自动机+DP -

题目地址:http://poj.org/problem?id=3691 思路: 把所有节点建一棵trie树 那么我们要做的 就是把母串在树上搜索,而且在搜索的时候不会碰到危险节点 也即是对于节点j有条字母边a到son[j] , 1)如果son[j]是危险节点,那么换一条j的边 2)如果son[j]为空,就顺着前驱节点找另一个字母边a 3)如果以上都不是,那么比较a和插入母串的字符,如

BRCOCOLI的博客 350

poj3691DNA repair

#include #include #include #include using namespace std; const int N=1005; const int INF=0x3ffffff; int tot=0,dp[N][N]; struct node{ int son[4],fail; bool dan; }trie[N]; void init(){ f

coder_coder_coder的专栏 673
上一篇: POJ - 2406 Power Strings
下一篇: POJ - 1451 T9
WilliamCode
博客等级 码龄11年 118粉丝 105原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值