HNU 13108 Just Another Knapsack Problem DP + Trie树优化

题意:

  给你一个文本串,和一些模式串,每个模式串都有一个价值,让你选一些模式串来组成文本串,使获得的价值最大。每个模式串不止能用一次。

思路:

  多重背包,枚举文本串的每个位置和模式串,把该模式串拼接在当前位置,看下一个位置是否能得到更优值。但是,存在很多模式串不能拼在当前位置的,无效状态。所以可以用Trie树来优化转移。

代码:

  

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <string>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <functional>
#include <cctype>
#include <time.h>

using namespace std;

const int INF = 1<<30;
const int MAXN = 1e5+5;
const int MAXLEN = 333;
const int MAXNODE = 1e5+5;;

struct Trie {
    int ch[MAXNODE][26];
    int val[MAXNODE], use;

    inline void init() {
        for (int i = 0; i < 26; i++) ch[0][i] = 0;
        val[0] = 0;
        use = 1;
    }
    inline int New() {
        for (int i = 0; i < 26; i++) ch[use][i] = 0;
        val[use] = 0;
        return use++;
    }
    inline int idx(char c) {
        return c - ‘a‘;
    }
    void insert(char str[], int v) {
        int len = strlen(str);
        int p = 0;
        for (int i = 0; i < len; i++) {
            int c = idx(str[i]);
            if (!ch[p][c]) ch[p][c] = New();
            p = ch[p][c];
        }
        val[p] = max(val[p], v);
    }
    int solve(char S[], int dp[]) {
        int len = strlen(S);
        for (int i = 0; i <= len; i++) dp[i] = -1;
        dp[0] = 0;
        for (int i = 0; i < len; i++) {
            if (dp[i]<0) continue;
            for (int j = i, p = 0; j <= len; j++) {
                int c = idx(S[j]);
                if (val[p]) dp[j] = max(dp[j], dp[i]+val[p]);
                p = ch[p][c];
                if (p==0) break;
            }
        }
        return max(dp[len], 0);
    }
};

Trie solver;

char S[MAXN], P[MAXLEN];
int dp[MAXN];
int m, v;

int main() {
    #ifdef Phantom01
        freopen("HNU13108.txt", "r", stdin);
    #endif //Phantom01

    while (scanf("%s", S)!=EOF) {
        scanf("%d", &m);
        solver.init();
        for (int i = 0; i < m; i++) {
            scanf("%s%d", P, &v);
            solver.insert(P, v);
        }
        printf("%d\n", solver.solve(S, dp));
    }

    return 0;
}

时间: 2024-11-05 19:03:03

HNU 13108 Just Another Knapsack Problem DP + Trie树优化的相关文章

【AC自动机+DP】HNU 13108 Just Another Knapsack Problem

通道:http://acm.hnu.cn/online/?action=problem&type=show&id=13108&courseid=296 题意:N个匹配串及权值,求完全匹配模式串的最大值. 思路:建AC自动机,dp[i]到达i的最大值,dp[i]=max(dp[i-L]+W); 代码:https://github.com/Mithril0rd/Rojo/blob/master/hnu13108.cpp

题解 HDU 3698 Let the light guide us Dp + 线段树优化

http://acm.hdu.edu.cn/showproblem.php?pid=3698 Let the light guide us Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 62768/32768 K (Java/Others) Total Submission(s): 759    Accepted Submission(s): 253 Problem Description Plain of despair was

2016&quot;百度之星&quot; - 资格赛(Astar Round1) Problem C (Trie树)

题意:对单词根据前缀进行插入,插入,和查询操作,查询的话存在即可. 因为之前几乎没怎么做过类似的题,再加上这次做的时候,对题意理解的不到位,所以错了很多次,以后要先把题意理解透彻再敲代码,这样会避开之后修改的很多不必要的细节错误. 思路:Trie树,root根节点通过next指针数组连接着26个相同的结点,分别代表26个英文字母,对应着第一个字母,同理,之后的字母也这么建立.这样树形结构就出来了.结构体里的num为记录以当前字符串为前缀的单词的数目. (1)insertNode:插入单词,如果之

HDU4719-Oh My Holy FFF(DP线段树优化)

Oh My Holy FFF Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total Submission(s): 606    Accepted Submission(s): 141 Problem Description N soldiers from the famous "*FFF* army" is standing in a line, from le

hdu 4719 Oh My Holy FFF(dp线段树优化)

Oh My Holy FFF Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total Submission(s): 848    Accepted Submission(s): 219 Problem Description N soldiers from the famous "*FFF* army" is standing in a line, from le

Codeforces 633C Spy Syndrome 2(DP+Trie树)

题目大概说给一个加密的字符串,加密规则是把原文转化成小写字母,然后各个单词反转,最后去掉空格.现在给几个已知的单词,还原加密的字符串. 和UVa1401一个道理.. 用dp[i]表示加密字符前i个字符都被解密时,最后所用单词编号,为0表示不能被解密 然后转移一个样,从i出发往前在Trie树上跑,看看能否找到不为0的dp[j],而str[j+1]str[j+2]...str[i-1]str[i]是单词 最后输出方案就根据dp里面的值从最后面回溯找到并输出即可 时间复杂度O(加密字符串长*单词最大长

hdu 5687 Problem C trie树

Problem C Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Problem Description 度熊手上有一本神奇的字典,你可以在它里面做如下三个操作: 1.insert : 往神奇字典中插入一个单词 2.delete: 在神奇字典中删除所有前缀等于给定字符串的单词 3.search: 查询是否在神奇字典中有一个字符串的前缀等于给定的字符串 Input 这里仅有

Codeforces 528B Clique Problem dp+线段树(or 树状数组)

题目链接:点击打开链接 题意: 给定数轴上的n个点. 下面n行每行两个数 xi, wi 表示点和点权. 对于任意两个点u, v 若dis(u,v) >= u_w+v_w 则这两个点间可以建一条边.(in other words 若两点间距离大于两点的权值和则可以建边) 找一个最大团,输出这个最大团的点数. 其实对于一个权值点我们可以认为是一个区间 如: 4 5 ,可以认为是区间[-1, 9] 则这个点可以从区间(-inf, 1]转移过来,即val(9) = max(val(9), 区间(-inf

hdu3698 Let the light guide us dp+线段树优化

http://acm.hdu.edu.cn/showproblem.php?pid=3698 Let the light guide us Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 62768/32768 K (Java/Others) Total Submission(s): 821    Accepted Submission(s): 285 Problem Description Plain of despair was