NUBT 1222 English Game 【字典树 + dp】

来源:互联网 发布:锦衣卫知乎 编辑:程序博客网 时间:2024/06/06 02:39

大一时比赛的剩题,今天不经意发现了。

题目链接:点我


题意:给定目标串str和n个短串以及每个短串的权值,现在让你从n个短串里面选若干个连接成str串。若可以得到目标串,输出最大的权值和(选出的短串权值和),反之输出-1。要求每个短串只能用一次。


思路:建立一棵trie,标记短串末尾。

设置dp[i]为 构成(str[i]-末尾)子串的最大权值和。每次可以从str[i]字符沿着trie向下走,走到字符str[j],若该字符为短串末尾则有:dp[i] = max(End[node] + dp[j+1])。也就是说字符str[i] - str[j]构成了该短串。

(node是trie上短串的末尾节点,End[node]为该短串的权值)。然后套个记忆化就OK了。


AC代码:


#include <iostream>#include <cstdio>#include <cmath>#include <cstring>#include <algorithm>#define ll o<<1#define rr o<<1|1#define CLR(a, b) memset(a, (b), sizeof(a))using namespace std;typedef long long LL;const int MAXN = 3*1e4+10;int L, next[MAXN][30], root, End[MAXN];int newnode(){    for(int i = 0; i <= 25; i++)        next[L][i] = -1;    End[L] = -1; L++;    return L-1;}void init() {L = 0; root = newnode();}void Insert(char *s, int val){    int u = root;    for(int i = 0; s[i]; i++)    {        int v = s[i] - 'a';        if(next[u][v] == -1)            next[u][v] = newnode();        u = next[u][v];    }    End[u] = val;}const int MAXM = 1e4+10;char str[MAXM]; int n, dp[MAXM];int len;int DFS(int pos){    if(pos >= len) return 0;    if(dp[pos] != -1) return dp[pos];    int u = root; int ans = -2;    for(int i = pos; str[i]; i++)    {        int v = str[i] - 'a';        if(next[u][v] == -1) break;        u = next[u][v];        if(End[u] != -1)        {            int temp = DFS(i+1);            if(temp != -2) ans = max(ans, End[u] + temp);        }    }    return dp[pos] = ans;}int main(){    while(scanf("%d%s", &n, &str) != EOF)    {        init(); char ss[35]; int v;        for(int i = 0; i < n; i++)        {            scanf("%s%d", &ss, &v);            Insert(ss, v);        }        len = strlen(str); CLR(dp, -1); DFS(0);        printf(dp[0] > 0 ? "%d\n" : "-1\n", dp[0]);    }    return 0;}


0 0
原创粉丝点击