QDU65 again and again(字典序暴力or字典树)
xx学习了Trie树后,向你问了一个问题,给定一个字符串集合S={str1, str2, …,strn}和一个字符串s,在s的后面接尽量少的字符,使其属于集合S。当然如果s本身就属于S,s就是答案。
第一行一个正整数T(T <= 10),表示有T组数据。 每组数据输入格式如下: 第一行为一个正整数N(0<N<20000),表示字符串集合内的字符串数。 接下来N行,每行一个字符串,表示集合中的串。 接下来一行是一个正整数Q(0<Q<200),表示有Q次询问。 接下来Q行,每行一个字符串str。 所有字符串均由小写英文字母组成,且1<=长度<=20。
每组数据输出格式如下: 先输出“Case x:”,x表示是第几组数据,然后输出一个换行。 接下来输出Q行,对于每次询问,如果str能够添加字符使其属于字符串集合,则输出长度最小的(即str添加字符后构成的串),有多个满足条件的话输出字典序最小的。否则输出-1。
复制
3 3 abc abd aba 3 ab ad abc 2 bcde bcdef 1 bcd 3 abc def hig 1 kkkk
Case 1: aba -1 abc Case 2: bcde Case 3: -1
字典树写法:
#include <bits/stdc++.h> using namespace std; int T; int N; char s[100]; int dp[500010]; int NN[500010]; int ch[500010]; struct tire { int L,root,End[500010], Next[500010][27]; int newnode() { for(int i=0; i<26; i++) Next[L][i] = -1; End[L++] = 0; return L-1; } void init() { L = 0; root = newnode(); } void insert(char *tmp) { int len = strlen(tmp); int now = root; for(int i=0; i<len; i++) { if(Next[now][s[i]-'a'] == -1) Next[now][s[i]-'a'] = newnode(); now = Next[now][s[i]-'a']; } End[now] = 1; } void dfs(int now) { if(End[now] == 1) { dp[now] = 0; } for(int i=0; i<26; i++) { int nn = Next[now][i]; if(nn != -1) { dfs(nn); if(dp[now] > dp[nn] + 1) { dp[now] = dp[nn] + 1; NN[now] = nn; ch[now] = i; } else if(dp[now] == dp[nn] + 1 && ch[now] > i) { NN[now] = nn; ch[now] = i; } } } } int query(char *tmp) { int len = strlen(tmp); int now = root; for(int i=0; i<len; i++) { if(Next[now][s[i]-'a'] == -1) return -1; now = Next[now][s[i]-'a']; } return now; } } Trie; int q; int main() { cin>>T; int icase = 0; while(T--) { memset(NN, -1, sizeof(NN)); memset(ch, -1, sizeof(ch)); memset(dp, 0x3f3f3f3f, sizeof(dp)); cin>>N; Trie.init(); for(int i=1; i<=N; i++) { scanf("%s", s); Trie.insert(s); } Trie.dfs(Trie.root); cin>>q; printf("Case %d:\n", ++icase); while(q--) { scanf("%s", s); int res = Trie.query(s); if(res == -1) { printf("-1\n"); continue; } printf("%s", s); while(true) { if(Trie.End[res] == 1) break; printf("%c", (char)(ch[res] + 'a')); res = NN[res]; } printf("\n"); } } return 0; }
暴力写法:
#include <bits/stdc++.h> using namespace std; struct Node { char str[25]; int len; }; Node node[20010]; bool cmp(Node x, Node y) { return (x.len < y.len || (x.len == y.len && strcmp(x.str, y.str) < 0)); } int main() { int t, tt = 1; scanf("%d", &t); while(t--) { int n; scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%s", node[i].str); node[i].len = strlen(node[i].str); } sort(node + 1, node + 1 + n, cmp); int q; printf("Case %d:\n", tt++); scanf("%d", &q); while(q--) { char str[25]; scanf("%s", str); int i; for(i = 1; i <= n; i++) { if(strstr(node[i].str, str) == node[i].str) { printf("%s\n", node[i].str); break; } } if(i == n + 1) printf("-1\n"); } } return 0; }