hdu2457 Trie图+dp

hdu2457

给定n个模式串, 和一个文本串

问如果修改最少的字符串使得文本串不包含模式串,

输出最少的次数,如果不能修改成功,则输出-1

dp[i][j] 表示长度为i的字符串, 到达状态j(Trie图中的结点)所需要修改的最少次数

那么dp[0->n][0->size] = INF ,  dp[0][root] = 0,  n代表字符串长度, size代表状态数

那么答案就是  min{dp[n][size]}

我们根据模式串所建的Trie图, 进行模拟构造不包含模式串的字符串

从第一个字符串开始构造,依次递增,在构造此字符的同时,比较是否和输入串的该字符串相等,

如果相等,则表示该位置的字符不需要改变, 如果不同,则表示该位置的字符需要改变

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <stdlib.h>
  4 #include <algorithm>
  5 #include <iostream>
  6 #include <queue>
  7 #include <stack>
  8 #include <vector>
  9 #include <map>
 10 #include <set>
 11 #include <string>
 12 #include <math.h>
 13 using namespace std;
 14 #pragma warning(disable:4996)
 15 typedef long long LL;
 16 const int INF = 1<<30;
 17 /*
 18
 19 */
 20 struct Node
 21 {
 22     int fail, next[4];
 23     bool isWord;
 24     void init()
 25     {
 26         fail = -1;
 27         isWord = false;
 28         for (int i = 0; i < 4; ++i)
 29             next[i] = -1;
 30
 31     }
 32 }Trie[1000 + 10];
 33 int size;
 34 char str[1000 + 10];
 35 int dp[1000 + 10][1000 + 10];
 36 int getCode(char ch)
 37 {
 38     if (ch == ‘A‘)
 39         return 0;
 40     if (ch == ‘G‘)
 41         return 1;
 42     if (ch == ‘C‘)
 43         return 2;
 44     return 3;
 45 }
 46 void insert(int root, char str[])
 47 {
 48     int cur = root;
 49     for (int i = 0; str[i]; ++i)
 50     {
 51         int idx = getCode(str[i]);
 52         if (Trie[cur].next[idx] == -1)
 53         {
 54             Trie[size].init();
 55             Trie[cur].next[idx] = size++;
 56         }
 57         cur = Trie[cur].next[idx];
 58     }
 59     Trie[cur].isWord = true;
 60 }
 61 void makeFail(int root)
 62 {
 63     queue<int> q;
 64     int cur;
 65     for (int i = 0; i < 4; ++i)
 66     if (Trie[root].next[i] == -1)
 67         Trie[root].next[i] = root;
 68     else
 69     {
 70         Trie[Trie[root].next[i]].fail = root;
 71         q.push(Trie[root].next[i]);
 72     }
 73     while (!q.empty())
 74     {
 75         cur = q.front();
 76         q.pop();
 77         for (int i = 0; i < 4; ++i)
 78         {
 79             if (Trie[Trie[cur].fail].isWord)
 80                 Trie[cur].isWord = true;
 81             if (Trie[cur].next[i] == -1)
 82                 Trie[cur].next[i] = Trie[Trie[cur].fail].next[i];
 83             else
 84             {
 85                 Trie[Trie[cur].next[i]].fail = Trie[Trie[cur].fail].next[i];
 86                 q.push(Trie[cur].next[i]);
 87             }
 88         }
 89     }
 90 }
 91
 92 //dp[i][j] 表示长度为i的字符串到达状态j,所要修改的次数,  如果状态为危险状态,那么肯定是INF
 93 int solve(int root, char *str)
 94 {
 95     int n = strlen(str);
 96     for (int i = 0; i <= n; ++i)
 97     for (int j = 0; j < size; ++j)
 98         dp[i][j] = INF;
 99
100     dp[0][root] = 0;
101     for (int i = 0; i < n; ++i)
102     for (int j = 0; j < size; ++j)
103     if (dp[i][j] < INF)
104     {
105         for (int k = 0; k < 4; ++k)
106         {
107             int next = Trie[j].next[k];
108             if (Trie[next].isWord) continue;
109             int tmp;
110             if (k == getCode(str[i]))
111                 tmp = dp[i][j];//如果构造出的字符和输入字符相同,就不需要改变该位置的字符串
112             else
113                 tmp = dp[i][j] + 1;//否则,要改变该位置的字符串
114             dp[i + 1][next] = min(dp[i + 1][next], tmp);
115         }
116     }
117     int ans = INF;
118     for (int j = 0; j < size; ++j)
119         ans = min(ans, dp[n][j]);
120     if (ans == INF) ans = -1;
121     return ans;
122 }
123
124 int main()
125 {
126     int n, k = 1;
127     char segment[20+10];
128     while(scanf("%d", &n), n)
129     {
130         Trie[0].init();
131         Trie[0].fail = 0;
132         size = 1;
133         for (int i = 0; i < n; ++i)
134         {
135             scanf("%s", segment);
136             insert(0, segment);
137         }
138         makeFail(0);
139         scanf("%s", str);
140         printf("Case %d: %d\n", k, solve(0, str));
141         k++;
142
143     }
144     return 0;
145 }
时间: 2024-09-30 20:08:06

hdu2457 Trie图+dp的相关文章

POJ 1625 Censored ( Trie图 &amp;&amp; DP &amp;&amp; 高精度 )

题意 : 给出 n 个单词组成的字符集 以及 p 个非法串,问你用字符集里面的单词构造长度为 m 的单词的方案数有多少种? 分析 :先构造出 Trie 图方便进行状态转移,这与在 POJ 2278 中的步骤是一样的,只不过最后的DP状态转移方式 2778 是利用了矩阵进行转移的,那是因为需要构造的串的长度非常长!只能利用矩阵转移.但是这道题需要构造的串的长度最多也就只有 50 ,可以利用普通的DP方法进行转移.我们定义 DP[i][j] 为以长度为 i 以字符 j 为结尾的串的种类数是多少,那么

hiho一下 第二周&amp;第四周:从Trie树到Trie图

hihocoder #1014 题目地址:http://hihocoder.com/problemset/problem/1014 hihocoder #1036 题目地址: http://hihocoder.com/problemset/problem/1036 trie图其实就是trie树+KMP #1014trie树 #include<stdio.h> #include <algorithm> #include <cstring> #include <str

Trie图 &amp; AC自动机初学(1)

题目来源于:Hihocoder 时间限制:20000ms 单点时限:1000ms 内存限制:512MB 描述 前情回顾 上回说到,小Hi和小Ho接受到了河蟹先生伟大而光荣的任务:河蟹先生将要给与他们一篇从互联网上收集来的文章,和一本厚厚的河蟹词典,而他们要做的是判断这篇文章中是否存在那些属于河蟹词典中的词语. 当时,小Hi和小Ho的水平还是十分有限,他们只能够想到:"枚举每一个单词,然后枚举文章中可能的起始位置,然后进行匹配,看能否成功."这样非常朴素的想法,但是这样的算法时间复杂度是

Trie图

DFA 确定性有限状态自动机 DFA确定性有限状态自动机是一种图结构的数据结构,可以由(Q, q0, A, Sigma, Delta)来描述,其中Q为状态集,q0为初始状态,A为终态集合,Sigma为字母表,Delta为转移函数.它表示从唯一一个起始状态q0开始,经过有限步的Delta转移,转移是根据字母表Sigma中的元素来进行,最终到达终态集合A中的某个状态的状态移动.  如图所示是一个终态集合为{"nano"}的DFA.     DFA只能有一个起点而可以有多个终点.每个节点都有

hihoCoder#1036 Trie图

原题地址 看了这篇博文,总算是把Trie图弄明白了 Runtime Error了无数次,一直不知道为什么,于是写了个脚本生成了一组大数据,发现果然段错误了. 调试了一下午,总算闹明白了,为什么呢? 1. 空间超大的变量不要放在函数里,会爆栈,应该弄成全局变量或者是从堆上动态分配. 2. 看清题目的数据范围,一开始我的MAX_NODE设的是1024... 代码: 1 #include <iostream> 2 #include <cstring> 3 4 using namespac

【hihoCoder】1036 Trie图

题目:http://hihocoder.com/problemset/problem/1036 给一个词典dict,词典中包含了一些单词words.要求判断给定的一个文本串text中是否包含这个字典中的单词words. 相关基础的理解 1. 与用KMP解决的问题的差别 KMP:输入原串S和一个模式串T,判断T是否出现在S中.通过对T计算next数组,避免原串S的回溯. 现在的问题:输入文本串text和多个单词words,判断words中是否有出现在text中.同样希望输入的text不用进行回溯.

hihocoder 1036 Trie图(AC自动机)

传送门 Description 上回说到,小Hi和小Ho接受到了河蟹先生伟大而光荣的任务:河蟹先生将要给与他们一篇从互联网上收集来的文章,和一本厚厚的河蟹词典,而他们要做的是判断这篇文章中是否存在那些属于河蟹词典中的词语. 当时,小Hi和小Ho的水平还是十分有限,他们只能够想到:“枚举每一个单词,然后枚举文章中可能的起始位置,然后进行匹配,看能否成功.”这样非常朴素的想法,但是这样的算法时间复杂度是相当高的,如果说词典的词语数量为N,每个词语长度为L,文章的长度为M,那么需要进行的计算次数是在N

[hiho 04]Trie图

题目描述 Trie 图就是在 Trie 树上建立 fail 指针,类似于KMP算法中的next数组的作用. 这个数据结构的作用是判断一个字符串中是否包含一组字符串中的任意一个. 结构体定义是这样的: typedef struct trie_node { trie_node *nodes[26]; trie_node *fail = NULL; bool word_end = false; trie_node() { for (int i = 0; i < 26; i++) { nodes[i]

【Trie图】BZOJ3940-[Usaco2015 Feb]Censoring

[题目大意] 有一个匹配串和多个模式串,现在不断删去匹配串中的模式串,求出最后匹配串剩下的部分. [思路] 众所周知,KMP的题往往对应着一道AC自动机quq.本题同BZOJ3942(KMP),这里改成AC自动机即可. 我一开始写了原始的AC自动机,写挂了.后来思考了一下,应当用Trie图,机智地1A. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm&