USACO 2.3.1 Longest Prefix

题目意思就是给定1~200个短的Primitive(长度1~10),以及一个长字符串(长度200,000以内),需要找出由这些Primitive任意重复连接形成的后者的最长前缀。

DP + Trie

设长字符串为seq,基本思路是若seq[0...i]是满足要求的前缀,那么seq[0...i+len]也是满足要求的前缀,len是各个Primitive的长度。

然后就是用Trie优化一下判断seq[i...i+len]是否在Primitive集合的过程。

View Code
  1 /*
  2 ID: xjtuacm1
  3 PROG: prefix
  4 LANG: C++
  5 */
  6 #include<iostream>
  7 #include<stack>
  8 #include<cstring>
  9 #include<cstdio>
 10 #include<queue>
 11 #include<algorithm>
 12 #include<map>
 13 #include<set>
 14 using namespace std;
 15 
 16 const int PRISIZE = 205;
 17 const int PRILEN = 10 + 1;
 18 const int SEQLEN = 200005;
 19 const int LINELEN = 76 + 2;
 20 
 21 struct _trie
 22 {
 23     int next[26];
 24     int cnt;
 25 } trie[PRISIZE * PRILEN];
 26 int trieNodeCnt;
 27 
 28 int trieInit()
 29 {
 30     memset(trie, 0, sizeof(trie));
 31     trieNodeCnt = 1;
 32 
 33     return 0; // trie tree's root
 34 }
 35 
 36 void trieAdd(int root, const char *str)
 37 {
 38     int p = root;
 39     while(*str)
 40     {
 41         if(trie[p].next[*str - 'A'] == 0)
 42         {
 43             trie[p].next[*str - 'A'] = trieNodeCnt++;
 44         }
 45         p = trie[p].next[*str - 'A'];
 46         str++;
 47     }
 48     trie[p].cnt += 1;
 49 }
 50 
 51 bool trieSearch(int root, const char* str, int len)
 52 {
 53     int p = root;
 54     for(int i = 0; i!= len; i++)
 55     {
 56         if(trie[p].next[str[i] - 'A'] == 0)
 57             return false;
 58 
 59         p = trie[p].next[str[i] - 'A'];
 60     }
 61 
 62     return trie[p].cnt > 0;
 63 }
 64 
 65 char seq[SEQLEN];
 66 int seqlen = 0;
 67 bool reach[SEQLEN]; // reach[i] =  if seq[0...i) (length = i) can be composed from primitives.
 68 
 69 int main(int argc, char *argv[])
 70 {
 71     freopen("prefix.in", "r", stdin);
 72 #ifndef USACO
 73     freopen("prefix.out", "w", stdout);
 74 #endif // USACO
 75 
 76     int root = trieInit(); // root = 0
 77     memset(reach, false, sizeof(reach));
 78 
 79     char temp[PRILEN];
 80     for(int i = 0; i!= PRISIZE; i++)
 81     {
 82         scanf("%s", temp);
 83         if(temp[0] == '.')
 84             break;
 85 
 86         trieAdd(root, temp);
 87     }
 88 
 89     while(true)
 90     {
 91         scanf("%s", seq + seqlen);
 92         int len = strlen(seq + seqlen);
 93         if(len == 0)
 94             break;
 95 
 96         seqlen += len;
 97     }
 98 
 99     for(int i = 1; i!= PRILEN; i++)
100     {
101         reach[i] = trieSearch(root, seq, i);
102     }
103 
104     for(int i = 0; i!= seqlen; i++)
105     {
106         if(reach[i])
107         {
108             for(int j = 1; j!= PRILEN; j++)
109             {
110                 if(trieSearch(root, seq + i, j))
111                     reach[i + j] = true;
112             }
113         }
114     }
115 
116     for(int i = seqlen ; i != 0; i--)
117     {
118         if(reach[i])
119         {
120             printf("%d\n", i);
121             return 0;
122         }
123     }
124 
125     printf("0\n");
126     return 0;
127 }

BTW,这是我第一次写Trie,感觉还挺顺手的。

转载于:https://www.cnblogs.com/tech-cabin/archive/2013/02/05/2892960.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值