https://www.acmicpc.net/problem/5052
트라이를 이용하면 된다.
전화번호 목록을 받아서 긴 길이->짧은 길이 순으로 정렬한다.
그 후에 insert를 하기전에 이 전화번호가 다른곳에 포함되있는지 확인한다.
#include<queue> #include<cstdio> #include<cstring> #include<cassert> #include<iostream> #include<string> #include<vector> #include <algorithm> using namespace std; const int ALPHABETS = 10; int toNumber(char ch) { return ch - '0'; } struct LinkedListNode { int elem; LinkedListNode* next; LinkedListNode(int _elem, LinkedListNode* _next) : elem(_elem), next(_next) { } }; // 트라이의 한 노드를 나타내는 객체 struct TrieNode { TrieNode* children[ALPHABETS]; // 이 노드가 종료 노드인가? bool terminal; TrieNode() : terminal(false) { memset(children, 0, sizeof(children)); } ~TrieNode() { for(int i = 0; i < ALPHABETS; i++) if(children[i]) delete children[i]; } // 이 노드를 루트로 하는 트라이에 문자열 key 를 추가한다. void insert(const char* key) { // 문자열이 끝나면 terminal 만 참으로 바꾸고 종료 if(*key == 0) terminal = true; else { int next = toNumber(*key); // 해당 자식 노드가 없다면 생성한다 if(children[next] == NULL) children[next] = new TrieNode(); // 해당 자식 노드로 재귀호출 children[next]->insert(key + 1); } } // 이 노드를 루트로 하는 트라이에 문자열 key 와 대응되는 노드를 찾는다. // 없으면 NULL 을 반환한다. TrieNode* find(const char* key) { if(*key == 0) return this; int next = toNumber(*key); if(children[next] == NULL) return NULL; return children[next]->find(key+1); } }; char phone[10000][11]; bool _reverse(pair<int ,char* > a, pair<int, char* > b) { return a.first > b.first; } int main() { int t; cin>>t; for(int i=0;i<t;i++) { TrieNode *trie = new TrieNode(); int n; vector<pair<int, char*>> save; cin>>n; for(int j=0;j<n;j++) { cin>>phone[j]; save.push_back(make_pair(strlen(phone[j]), phone[j])); } sort(save.begin(),save.end(),_reverse); //for(int j=0;j<n;j++) // cout<<j<<" = "<<save[j].first<<" "<<save[j].second<<endl; bool flag = true; for(int j=0;j<n;j++) { if(j>0 && trie->find(save[j].second)) flag=false; trie->insert(save[j].second); } if(flag) cout<<"YES\n"; else cout<<"NO\n"; } return 0; }
https://www.acmicpc.net/problem/9250
카테고리에 적어놓은 아호코라식 기본 소스코드에서 ahoCorasick함수, test함수만 변경하고
입력받아서 실행하면 된다.
#include<map> #include<queue> #include<cstdio> #include<cstring> #include<cassert> #include<iostream> #include<string> #include<vector> using namespace std; // 알파벳 소문자를 저장하는 경우 각 노드는 26개의 자손을 가질 수 있다 const int ALPHABETS = 26; int toNumber(char ch) { return ch - 'a'; } struct LinkedListNode { int elem; LinkedListNode* next; LinkedListNode(int _elem, LinkedListNode* _next) : elem(_elem), next(_next) { } }; struct TrieDict { TrieDict* children[ALPHABETS]; int terminal; // 이 노드에서 매칭이 실패했을 때 이 곳으로 가서 계속한다. // 이 노드에 대응되는 문자열의 접미사이면서 트라이에 포함된 최대 문자열. TrieDict* fail; // 이 노드가 방문되었을 때 등장하는 문자열들의 번호 LinkedListNode* output; TrieDict() : terminal(-1), output(NULL) { memset(children, 0, sizeof(children)); } ~TrieDict() { for(int i = 0; i < ALPHABETS; i++) if(children[i]) delete children[i]; } // 이 노드를 루트로 하는 트라이에 번호가 id 인 문자열 key 를 추가한다 void insert(const char* key, int id) { // 문자열이 끝나면 terminal 만 참으로 바꾸고 종료 if(*key == 0) terminal = id; else { int next = toNumber(*key); // 해당 자식 노드가 없다면 생성한다 if(children[next] == NULL) children[next] = new TrieDict(); // 해당 자식 노드로 재귀호출 children[next]->insert(key + 1, id); } } TrieDict* find(const char* key) { if(*key == 0) return this; int next = toNumber(*key); if(children[next] == NULL) return NULL; return children[next]->find(key+1); } }; void calcFailureFunction(TrieDict* root) { queue<TrieDict*> q; // 루트의 fail 함수는 자기 자신 root->fail = root; q.push(root); while(!q.empty()) { TrieDict* here = q.front(); q.pop(); for(int edge = 0; edge < ALPHABETS; ++edge) { if(!here->children[edge]) continue; TrieDict* child = here->children[edge]; // 1레벨 노드의 실패 연결은 항상 루트 if(here == root) child->fail = root; else { TrieDict* t = here->fail; while(t != root && t->children[edge] == NULL) t = t->fail; if(t->children[edge]) t = t->children[edge]; child->fail = t; } if(child->terminal != -1) child->output = new LinkedListNode(child->terminal, child->fail->output); else child->output = child->fail->output; q.push(child); } } } template<class CALLBACK> bool ahoCorasick(const string& s, TrieDict* trie, CALLBACK callback) { TrieDict* state = trie; for(int i = 0; i < s.size(); i++) { int chr = toNumber(s[i]); while(state != trie && state->children[chr] == NULL) state = state->fail; if(state->children[chr]) state = state->children[chr]; for(LinkedListNode* t = state->output; t; t = t->next) return callback(i, t->elem); } return false; } TrieDict* find(TrieDict* node, const char* key) { if(*key == 0) return node; int next = toNumber(*key); if(node->children[next] == NULL) return NULL; return find(node->children[next], key+1); } bool test(int a, int b) { return true; } int main() { int n,q; cin>>n; TrieDict* trie = new TrieDict(); for(int i=0;i<n;i++) { char str[101]; cin>>str; trie->insert(str, i); } calcFailureFunction(trie); cin>>q; for(int i=0;i<q;i++) { char str[10001]; cin>>str; if(ahoCorasick(string(str),trie,test)==1) cout<<"YES\n"; else cout<<"NO\n"; } return 0; }
'algorithm > problem solving' 카테고리의 다른 글
쉬어가기 (0) | 2016.09.29 |
---|---|
acmicpc.net 1717(Disjoint-set), 11866,1158(조세퍼스 문제.) (0) | 2016.09.28 |
acmicpc.net 5582(Suffix Automaton), 9249, 9253(Suffix Automaton) (0) | 2016.09.26 |
acmicpc.net 9248(접미사 배열), 1605,3033,1701(접미사 배열) (0) | 2016.09.26 |
acmicpc.net 1927,11279,11286(힙), 11055(LIS), 1956(플로이드) (0) | 2016.09.24 |