1
- // Authored by : BaaaaaaaaaaarkingDog
1
+ // Authored by : heheHwang
2
2
// Co-authored by : -
3
- // http://boj.kr/****************
3
+ // http://boj.kr/d335d203808e47d5a4f5f7dbe17ecdfb
4
4
#include < bits/stdc++.h>
5
5
using namespace std ;
6
6
7
- int main (void ){
7
+ const int ROOT = 1 , MX = 1e6 + 10 ;
8
+ int unused, keystroke_total;
9
+ bool chk[MX];
10
+ vector<pair<int , int >> nxt[MX]; // 자식을 동적 배열로 관리
11
+
12
+ // node의 자손 중, c에 해당하는 자손이 있는지 체크합니다.
13
+ int getchild (int node, char c) {
14
+ for (auto [id, c_] : nxt[node])
15
+ if (c == c_) return id;
16
+ return -1 ;
17
+ }
18
+ void insert (string& s) {
19
+ int curr = ROOT;
20
+ for (auto c : s) {
21
+ int child = getchild (curr, c);
22
+ if (child == -1 ) {
23
+ child = unused;
24
+ nxt[curr].push_back ({unused++, c});
25
+ }
26
+ curr = child;
27
+ }
28
+ chk[curr] = true ;
29
+ }
30
+ // dfs 탐색
31
+ void dfs (int curr, int key_strokes) {
32
+ if (chk[curr])
33
+ keystroke_total += ++key_strokes;
34
+ else if (nxt[curr].size () > 1 )
35
+ ++key_strokes;
36
+ for (auto [nxt_node, _] : nxt[curr])
37
+ dfs (nxt_node, key_strokes);
38
+ }
39
+ int main (void ) {
8
40
ios::sync_with_stdio (0 );
9
41
cin.tie (0 );
10
-
11
- }
42
+ cout << fixed;
43
+ cout.precision (2 );
44
+
45
+ int N;
46
+ while (cin >> N) {
47
+ for (int i = 0 ; i < MX; i++) nxt[i].clear ();
48
+ fill (chk, chk + MX, 0 );
49
+ unused = ROOT + 1 ;
50
+ keystroke_total = 0 ;
51
+
52
+ vector<string> words (N);
53
+ for (int i = 0 ; i < N; i++) cin >> words[i];
54
+ for (auto & s : words) insert (s);
55
+ for (auto [id, _] : nxt[ROOT]) dfs (id, 0 );
56
+ cout << 1.0 * keystroke_total / words.size () << ' \n ' ;
57
+ }
58
+ }
59
+ /*
60
+ 자판을 누르는 행위는 다음과 같은 경우에 이루어집니다.
61
+ 1. 단어 분기가 존재할 경우
62
+ 2. 단어가 완성되었을 경우
63
+ 이 두가지 경우에 맞추어서 적절하게 카운터를 올려주면서
64
+ 탐색해주면 자판을 누르는 횟수를 계산할 수 있습니다.
65
+
66
+ 유의점: 처음 한 번은 무조건 누르게 되어있으므로,
67
+ ROOT의 각 자식에서부터 탐색을 시작해야 합니다.
68
+
69
+ 메모리 절약을 위해 동적 배열로 구현했지만 자식을 26칸 배열로 두어도
70
+ 아마 통과에는 문제가 없을 것입니다.
71
+ */
0 commit comments