HDU 3341 Lost's revenge ( Trie图 && 状压DP && 数量限制类型 )
题意 : 给出 n 个模式串,最后给出一个主串,问你主串打乱重组的情况下,最多能够包含多少个模式串。
分析 : 如果你做过类似 Trie图 || AC自动机 + DP 类似的题目的话,那么这道题相对之前的对于主串的“构造”过程加上了一个限制,那就是字符的元素的有限制的,那么DP的状态就不能用长度来表示状态( 类比 POJ 2778 ),所以写出了一个错误的根据长度DP的代码
; i<len; i++){
; j<ac.Size; j++){
){
; k<; k++){
){///表示 i、j 状态下,0123代表的“ATGC”字符数还剩多少,但是这是错的,因为在长度为 i 停留在当前节点
///j 的字符串可能有多种,而这些字符串所拥有的剩余字符数是不一样的,不能单纯只用Lter[i][j][k]表示
///实际上这只是我自己的理解,我没有打表跟踪过错误数据,你可以自己想想为什么这样子不行……
;
int newj = ac.Node[j].Next[k];
dp[newi][newj] = max(dp[newi][newj], dp[i][j] + ac.Node[newj].cnt);
; l<; l++)
Lter[newi][newj][l] = Lter[i][j][l];
Lter[newi][newj][k]--;
}
}
}
}
}
那要如何定义DP状态呢?一般来说对于这样的数量和所在节点状态是关键点,所以我们可以DP[A][T][G][C][Node]前四维表示ATGC数量,最后一维表示当前状态停留在节点 Node ,但是这样子空间会爆炸,这时候就需要压缩一下状态,考虑压缩前四维,网上有很多利用进制的压缩,弱智的我有点不理解,所以还是用了普通的Hash,即利用一个四维数组 Hash[11][11][11][11] ( 每一个字母最多就是 10 个,所以这样开数组 ) ,然后只需要统计主串各个种类字符的数量,就能打出一个 Hash 表,将原本五维DP压成二维DP,DP[i][j] 表示各个字符数量状态为 i 且停留在 j 节点的最多包含模式串个数,则状态转移方程为 ( 一个节点状态能转到"ATGC"四个状态,那么以转到字符 ' A ' 为例 )
DP[ Hash[A+1][G][T][C] ][j] = max( DP[ Hash[A+1][G][T][C] ][j], DP[i][j] + Trie[j]['A'].cnt )
DP初始状态为 DP[0][0] = 0、DP[0~最大的Hash值数量][0~Trie图上的节点个数] = -1
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
;
* + ;
];
][][][];
struct Aho{
struct StateTable{
int Next[Letter];
int fail, cnt;
}Node[Max_Tot];
int Size;
queue<int> que;
inline void init(){
while(!que.empty()) que.pop();
memset(Node[].Next, , ].Next));
Node[].fail = Node[].cnt = ;
Size = ;
}
inline void insert(char *s){
;
; s[i]; i++){
int idx = mp[s[i]];
if(!Node[now].Next[idx]){
memset(Node[Size].Next, , sizeof(Node[Size].Next));
Node[Size].fail = Node[Size].cnt = ;
Node[now].Next[idx] = Size++;
}
now = Node[now].Next[idx];
}
Node[now].cnt++;
}
inline void BuildFail(){
Node[].fail = ;
; i<Letter; i++){
].Next[i]){
Node[Node[].Next[i]].fail = ;
que.push(Node[].Next[i]);
}].Next[i] = ;///必定指向根节点
}
while(!que.empty()){
int top = que.front(); que.pop();
Node[top].cnt += Node[Node[top].fail].cnt;
; i<Letter; i++){
int &v = Node[top].Next[i];
if(v){
que.push(v);
Node[v].fail = Node[Node[top].fail].Next[i];
}else v = Node[Node[top].fail].Next[i];
}
}
}
}ac;
];
***+][];
int Solve()
{
]; memset(num, , sizeof(num));
; S[i]; i++) num[mp[S[i]]]++;
;
; A<=num[]; A++)
; T<=num[]; T++)
; G<=num[]; G++)
; C<=num[]; C++)
Hash[A][T][G][C] = HashCnt++;
; j<=ac.Size; j++)
; i<=HashCnt; i++)
dp[i][j] = -;
dp[][] = ;
; A<=num[]; A++){
; T<=num[]; T++){
; G<=num[]; G++){
; C<=num[]; C++){
; i<ac.Size; i++){
int j = Hash[A][T][G][C];
){
; k<; k++){
&& A == num[]) continue;
&& T == num[]) continue;
&& G == num[]) continue;
&& C == num[]) continue;
int a, t, g, c;
a = (k==), t = (k==);
g = (k==), c = (k==);
dp[Hash[A+a][T+t][G+g][C+c]][ac.Node[i].Next[k]]
= max(dp[Hash[A+a][T+t][G+g][C+c]][ac.Node[i].Next[k]],
dp[j][i] + ac.Node[ac.Node[i].Next[k]].cnt);
}
}
}
}
}
}
}
;
]][num[]][num[]][num[]];
; i<ac.Size; i++)
ans = max(ans, dp[MaxNum][i]);
return ans;
}
int main(void)
{
;
mp[, mp[;
mp[, mp[;
while(~scanf("%d", &n) && n){
ac.init();
; i<n; i++){
scanf("%s", S);
ac.insert(S);
}ac.BuildFail();
scanf("%s", S);
printf("Case %d: %d\n", Case++, Solve());
}
;
}
HDU 3341 Lost's revenge ( Trie图 && 状压DP && 数量限制类型 )的更多相关文章
- HDU 4758 Walk Through Squares ( Trie图 && 状压DP && 数量限制类型 )
题意 : 给出一个 n 行.m 列的方格图,现从图左上角(0, 0) 到右下角的 (n, m)走出一个字符串(规定只能往下或者往右走),向右走代表' R ' 向下走则是代表 ' D ' 最后从左上角到 ...
- HDU 3920Clear All of Them I(状压DP)
HDU 3920 Clear All of Them I 题目是说有2n个敌人,现在可以发n枚炮弹,每枚炮弹可以(可以且仅可以)打两个敌人,每一枚炮弹的花费等于它所行进的距离,现在要消灭所有的敌人 ...
- HDU 5067 Harry And Dig Machine(状压dp)
HDU 5067 Harry And Dig Machine 思路:因为点才10个,在加上一个起点,处理出每一个点之间的曼哈顿距离,然后用状压dp搞,状态表示为: dp[i][s],表示在i位置.走过 ...
- HDU 3247 Resource Archiver(AC自动机 + 状压DP + bfs预处理)题解
题意:目标串n( <= 10)个,病毒串m( < 1000)个,问包含所有目标串无病毒串的最小长度 思路:貌似是个简单的状压DP + AC自动机,但是发现dp[1 << n][ ...
- HDU - 6125: Free from square (状压DP+分组背包)
problem:给定N,K.表示你有数1到N,让你最多选择K个数,问有多少种方案,使得选择的数的乘积无平方因子数.N,K<500: solution:显然可以状压DP做,但是500以内的素数还是 ...
- HDU 6984 - Tree Planting(数据分治+状压 dp)
题面传送门 傻逼卡常屑题/bs/bs,大概现场过得人比较少的原因就是它比较卡常罢(Fog 首先对于这样的题我们很难直接维护,不过注意到这个 \(n=300\) 给得很灵性,\(k\) 比较小和 \(k ...
- BZOJ 1195 [HNOI2006]最短母串 (Trie图+状压+bfs最短路)
BZOJ1195 LOJ10061 题目大意:给你$n$个模式串,求一个最短且字典序最小的文本串并输出这个串,$n<=12,len<=50$ 首先对所有模式串构造$Trie$图,$Trie ...
- 一本通 高手训练 1782 分层图 状压dp
LINK:分层图 很精辟的一道题 写的时候没带脑子 导致搞了半天不知道哪错了. 可以想到状压每次到某一层的状态 然后这个表示方案数 多开一维表示此时路径条数的奇偶即可. 不过显然我们只需要知道路径条数 ...
- hdu 6086 -- Rikka with String(AC自动机 + 状压DP)
题目链接 Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, s ...
随机推荐
- 个人推荐的两款vue导出EXCEL插件
个人认为前端VUE项目中导出EXCEL比较好的两种方法,均不是我个人原创,我只是收录简单说明,原创地址在下面. 下面推荐两种方法,个人推荐第一种,第二种不做详细讲解,因为作者已经写过博客了,你们可以点 ...
- 十、Zabbix-自动关联模板
之前的文章中,我们实现了自动注册,自动分组:并且创建了模板,监控项,触发器.为的就是能够实现主机自动被期望的监控项监控到.接下来我们只要能让自动注册的主机能够自动连接到我们设置好的模板,就可以实现自动 ...
- Python中classmethod和staticmethod的区别
学习python中经常会出现一些相近或者相似的语法模块等,需要对比分析才能加深记忆,熟练运用. staticmethod:静态方法 classmethod:类方法 在python中,静态方法和类方法都 ...
- 【嵌入式linux】用户登录密码验证配置
在配置BusyBox中配置登录密码: 配置位置BusyBox Setting --> General Configuration --> Suppo ...
- qt undefined reference to `vtable for subClass'
1. 建立一个console工程 QT -= gui CONFIG += c++ console CONFIG -= app_bundle # The following define makes y ...
- 通过编写串口助手工具学习MFC过程--(十一)弹出模态型对话框
通过编写串口助手工具学习MFC过程 因为以前也做过几次MFC的编程,每次都是项目完成时,MFC基本操作清楚了,但是过好长时间不再接触MFC的项目,再次做MFC的项目时,又要从头开始熟悉.这次通过做一个 ...
- python学习第五十四天hashlib模块的使用
hash算法 hash也做散列,也称为哈希,主要用于信息安全领域中加密算法,hash就是找一种数据内容和数据存放地址直接的映射关系. md5算法 md5讯息算法,广泛使用密码函数 md5算法的特点 1 ...
- go & flag
参考 Golang下的flag模块使用 Go基础篇[第6篇]: 内置库模块 flag
- vue梳理(2)
-app.vue作为根组件被挂载到index.html文件里,其他的所有组件都是在app.vue组件里做文章. 展示给用户的就是app.vue里的内容,你觉得删的没有内容了但实际还有很多是因为什么呢? ...
- C#人民币金额大写转换
人民币金额大小写转换,三行代码 //完善了一下查询到的方法,支持小数,保留2位小数 public string NumGetStr(double Num) { string[] DX_SZ = { & ...