这是一道AC自动机与dp结合的题目。
每个单词有一个权值,把一个长的单词分解成所给的几个单词,并要求尽量使所得到的权值最大,如果不能分解成所给的几个单词输出-1。
用dp[i] 表示到i个位置以前的单词分解所能得到的最大权值。那么当我们用ac自动机匹配到一个单词时就要更新
dp[pts+1] = max(dp[pts+1],dp[pts+1 - tmp->cnt] + tmp->value);
最后输出dp[len]的值即可
#include <iostream>
#include <string>
#include <memory.h>
#include <cstdio>
#include <algorithm>
using namespace std;
const int M = 5005;
const int N = 20006;
const int MAX_N = 26;
const int INF = 1 << 30;
struct TrieNode
{
TrieNode * next;
TrieNode * son[MAX_N];
bool end;
int cnt;
int value;
TrieNode()
{
next = NULL;
memset(son,0,sizeof(son));
end = false;
cnt = -INF;
value = -INF;
}
} *queue[M * 100],*root;
int n,dp[N],val;
char str[N];
void INIT();
void TrieInsert(char *);
void Build_AC_Automachine();
void AC_Search();
int main()
{
int t;
while(scanf("%d",&n)!=EOF)
{
INIT();
Build_AC_Automachine();
scanf("%s",&str);
AC_Search();
}
return 0;
}
void INIT()
{
char buf[103];
root = new TrieNode();
for(int i = 0;i < n;i++)
{
scanf("%s",&buf);
scanf("%d",&val);
TrieInsert(buf);
}
return;
}
void TrieInsert(char *buf)
{
int v,pts;
pts = 0;
TrieNode *ptt = root;
while(buf[pts])
{
v = buf[pts] - 'a';
if(ptt->son[v] == NULL)ptt->son[v] = new TrieNode();
ptt = ptt->son[v];
pts++;
}
ptt->end = true;
ptt->cnt = strlen(buf);
ptt->value = max(val,ptt->value);
return;
}
void Build_AC_Automachine()
{
int top;
top = 0;
queue[top++] = root;
root->next = NULL;
for(int i = 0;i < top;i++)
{
TrieNode *cur = queue[i];
for(int j = 0;j < 26;j++) if(cur->son[j]!=NULL)
{
if(cur == root)cur->son[j]->next = root;
else
{
TrieNode *ptt = cur->next;
while(ptt!= NULL)
{
if(ptt->son[j]!=NULL)
{
cur->son[j]->next = ptt->son[j];
if(ptt->son[j]->end == true)cur->son[j]->end = true;
break;
}
ptt = ptt->next;
}
if(ptt == NULL)cur->son[j]->next = root;
}
queue[top++] = cur->son[j];
}
}
return;
}
void AC_Search()
{
memset(dp,-1,sizeof(dp));
dp[0] = 0;
int pts;
pts = 0;
TrieNode *ptt = root;
while(str[pts])
{
int v = str[pts] - 'a';
while(ptt->son[v] == NULL && ptt != root)ptt = ptt->next;
ptt = ptt->son[v];
if(ptt == NULL)ptt = root;
TrieNode *tmp = ptt;
while(tmp != NULL)
{
if(dp[pts+1 - tmp->cnt] != -1 && tmp->value != -INF)
{
dp[pts+1] = max(dp[pts+1],dp[pts+1 - tmp->cnt] + tmp->value);
//pts加一是为了防止找第一个的时候找到-1位置,这样就无法估计结果了
}
tmp = tmp->next;
}
pts++;
}
int len = strlen(str);
printf("%d\n",dp[len]);
return;
}