POJ 3691 HDU 2457 DNA repair (AC自动机,DP)

2024-08-23 11:08

本文主要是介绍POJ 3691 HDU 2457 DNA repair (AC自动机,DP),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

http://poj.org/problem?id=3691

http://acm.hdu.edu.cn/showproblem.php?pid=2457

DNA repair
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 5690 Accepted: 2669

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

Source

2008 Asia Hefei Regional Contest Online by USTC


题意:

给出N个模式串和一个文本串,问最少修改文本串中多少个字母使得文本串中不包含模式串。

分析:

N个模式串构建AC自动机,然后文本串在AC自动机中走,其中单词结点不可达。

用dp[i][j]表示文本串第i个字母转移到AC自动机第j个结点最少修改字母的个数,状态转移方程为dp[i][j]=min(dp[i][j],dp[i-1][last]+add),last表示j的前趋,add为当前点是否修改。由于第i个只和第i-1个有关,所以可以使用滚动数组来优化空间。


/*** Author : fcbruce <fcbruce8964@gmail.com>** Time : Tue 18 Nov 2014 11:17:49 AM CST**/
#include <cstdio>
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <algorithm>
#include <ctime>
#include <cctype>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <queue>
#include <list>
#include <vector>
#include <map>
#include <set>
#define sqr(x) ((x)*(x))
#define LL long long
#define itn int
#define INF 0x3f3f3f3f
#define PI 3.1415926535897932384626
#define eps 1e-10#ifdef _WIN32#define lld "%I64d"
#else#define lld "%lld"
#endif#define maxm 
#define maxn 1024using namespace std;int q[maxn];const int maxsize = 4;
struct Acauto
{int ch[maxn][maxsize];bool val[maxn];int last[maxn],nex[maxn];int sz;int dp[2][maxn];Acauto(){memset(ch[0],0,sizeof ch[0]);val[0]=false;sz=1;}void clear(){memset(ch[0],0,sizeof ch[0]);val[0]=false;sz=1;}int idx(const char c){if (c=='A') return 0;if (c=='T') return 1;if (c=='C') return 2;return 3;}void insert(const char *s){int u=0;for (int i=0;s[i]!='\0';i++){int c=idx(s[i]);if (ch[u][c]==0){memset(ch[sz],0,sizeof ch[sz]);val[sz]=false;ch[u][c]=sz++;}u=ch[u][c];}val[u]=true;}void get_fail(){int f=0,r=-1;nex[0]=0;for (int c=0;c<maxsize;c++){int u=ch[0][c];if (u!=0){nex[u]=0;q[++r]=u;last[u]=0;}}while (f<=r){int x=q[f++];for (int c=0;c<maxsize;c++){int u=ch[x][c];if (u==0){ch[x][c]=ch[nex[x]][c];continue;}q[++r]=u;int v=nex[x];nex[u]=ch[v][c];val[u]|=val[nex[u]];}}}int DP(const char *T){memset(dp,0x3f,sizeof dp);dp[0][0]=0;int x=1;for (int i=0;T[i]!='\0';i++,x^=1){memset(dp[x],0x3f,sizeof dp[x]);int c=idx(T[i]);for (int j=0;j<sz;j++){if (dp[x^1][j]==INF) continue;for (int k=0;k<4;k++){if (val[ch[j][k]]) continue;int add=k==c?0:1;dp[x][ch[j][k]]=min(dp[x][ch[j][k]],dp[x^1][j]+add);}}}int MIN=INF;for (int i=0;i<sz;i++)MIN=min(MIN,dp[x^1][i]);if (MIN==INF) MIN=-1;return MIN;}
}acauto;char DNA[1024];int main()
{
#ifdef FCBRUCEfreopen("/home/fcbruce/code/t","r",stdin);
#endif // FCBRUCEint n,__=0;while (scanf("%d",&n),n!=0){acauto.clear();for (int i=0;i<n;i++){scanf("%s",DNA);acauto.insert(DNA);}acauto.get_fail();scanf("%s",DNA);printf("Case %d: %d\n",++__,acauto.DP(DNA));}return 0;
}


这篇关于POJ 3691 HDU 2457 DNA repair (AC自动机,DP)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1099206

相关文章

hdu4826(三维DP)

这是一个百度之星的资格赛第四题 题目链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1004&cid=500 题意:从左上角的点到右上角的点,每个点只能走一遍,走的方向有三个:向上,向下,向右,求最大值。 咋一看像搜索题,先暴搜,TLE,然后剪枝,还是TLE.然后我就改方法,用DP来做,这题和普通dp相比,多个个向上

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

hdu4865(概率DP)

题意:已知前一天和今天的天气概率,某天的天气概率和叶子的潮湿程度的概率,n天叶子的湿度,求n天最有可能的天气情况。 思路:概率DP,dp[i][j]表示第i天天气为j的概率,状态转移如下:dp[i][j] = max(dp[i][j, dp[i-1][k]*table2[k][j]*table1[j][col] )  代码如下: #include <stdio.h>#include

usaco 1.3 Barn Repair(贪心)

思路:用上M块木板时有 M-1 个间隙。目标是让总间隙最大。将相邻两个有牛的牛棚之间间隔的牛棚数排序,选取最大的M-1个作为间隙,其余地方用木板盖住。 做法: 1.若,板(M) 的数目大于或等于 牛棚中有牛的数目(C),则 目测 给每个牛牛发一个板就为最小的需求~ 2.否则,先对 牛牛们的门牌号排序,然后 用一个数组 blank[ ] 记录两门牌号之间的距离,然后 用数组 an

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

usaco 1.1 Broken Necklace(DP)

直接上代码 接触的第一道dp ps.大概的思路就是 先从左往右用一个数组在每个点记下蓝或黑的个数 再从右到左算一遍 最后取出最大的即可 核心语句在于: 如果 str[i] = 'r'  ,   rl[i]=rl[i-1]+1, bl[i]=0 如果 str[i] = 'b' ,  bl[i]=bl[i-1]+1, rl[i]=0 如果 str[i] = 'w',  bl[i]=b

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

hdu 2093 考试排名(sscanf)

模拟题。 直接从教程里拉解析。 因为表格里的数据格式不统一。有时候有"()",有时候又没有。而它也不会给我们提示。 这种情况下,就只能它它们统一看作字符串来处理了。现在就请出我们的主角sscanf()! sscanf 语法: #include int sscanf( const char *buffer, const char *format, ... ); 函数sscanf()和

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

poj 1511 Invitation Cards(spfa最短路)

题意是给你点与点之间的距离,求来回到点1的最短路中的边权和。 因为边很大,不能用原来的dijkstra什么的,所以用spfa来做。并且注意要用long long int 来存储。 稍微改了一下学长的模板。 stack stl 实现代码: #include<stdio.h>#include<stack>using namespace std;const int M