From 3679d7950d1cb1f32197d584679363914f2e4829 Mon Sep 17 00:00:00 2001 From: Cole Fuerth Date: Thu, 1 Dec 2022 15:36:12 -0500 Subject: [PATCH 01/12] fill out most of request template --- .github/pull_request_template.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 9ae4f93..fb9aa3a 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -3,13 +3,13 @@ PLEASE FILL IN THE FOLLOWING! ## Full Name -John Johnson +Cole Fuerth ## UWindsor Email -john.johnson@uwindsor.ca +fuert11g@uwindsor.ca ## Application Form -- [ ] I certify I have submitted the [application form](https://forms.office.com/r/R4A1JyB3Xf) +- [x] I certify I have submitted the [application form](https://forms.office.com/r/R4A1JyB3Xf) ## Briefly explain how your solution works and how to run it From 9b62e03a9dfe710db2aab25218635e1fb3798ce0 Mon Sep 17 00:00:00 2001 From: Cole Fuerth Date: Thu, 1 Dec 2022 15:36:21 -0500 Subject: [PATCH 02/12] get input read into the solution --- sample_input.txt | 4 ++++ solution.py | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 sample_input.txt create mode 100644 solution.py diff --git a/sample_input.txt b/sample_input.txt new file mode 100644 index 0000000..0f415ec --- /dev/null +++ b/sample_input.txt @@ -0,0 +1,4 @@ +A B C E +S F C S +A D E E +ABCCED \ No newline at end of file diff --git a/solution.py b/solution.py new file mode 100644 index 0000000..fd8ad97 --- /dev/null +++ b/solution.py @@ -0,0 +1,23 @@ + +if __name__ == '__main__': + + # assume input comes from stdin + # board input is single characters, space separated for columns and newlines for rows + # word is on its own line + # example input: + # ``` + # A B C E + # S F C S + # A D E E + # word + # ``` + board = [] + word = None + while (True): + line = input().split(" ") + if (len(line) == 1): + word = line[0] + break + board.append(line) + + \ No newline at end of file From 3e30b941401818b956884f249a082c47a49e5845 Mon Sep 17 00:00:00 2001 From: Cole Fuerth Date: Thu, 1 Dec 2022 16:16:45 -0500 Subject: [PATCH 03/12] complete, single threaded solution --- sample_input.txt | 2 +- solution.py | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/sample_input.txt b/sample_input.txt index 0f415ec..a70a1db 100644 --- a/sample_input.txt +++ b/sample_input.txt @@ -1,4 +1,4 @@ A B C E S F C S A D E E -ABCCED \ No newline at end of file +ABCB \ No newline at end of file diff --git a/solution.py b/solution.py index fd8ad97..ffc1e7c 100644 --- a/solution.py +++ b/solution.py @@ -1,3 +1,28 @@ +#/usr/bin/python3 + +from itertools import product + +def solve(points:set, s:str, grid:dict, path:set=None) -> bool: + # points is a list of tuples (x, y) for points to try to connect to the first character of s + # s is the string to connect, check the list of points to see if they can be connected to form s + # grid is the grid of characters + # path is a list of points that have been used to connect to s so far + # return True if s can be connected, False otherwise + if path is None: + path = set() + if len(s) == 0: + return True + for p in points: + if p in path: + continue + if s[0] == grid[p]: + path.add(p) + # list of points left, right, up, down from p that are in the grid keyset + adj = set([(p[0] + 1, p[1]), (p[0] - 1, p[1]), (p[0], p[1] + 1), (p[0], p[1] - 1)]).intersection(grid.keys()) + if solve(adj, s[1:], grid, path): + return True + path.remove(p) + return False if __name__ == '__main__': @@ -19,5 +44,12 @@ word = line[0] break board.append(line) + # convert board to a dictionary of (x, y) -> character + board = {(x, y): board[x][y] for x, y in product(range(len(board)), range(len(board[0])))} - \ No newline at end of file + # you take the input, and see if for each character, you can follow a path from character to character. The same character cannot be used more than once + print(solve( + set([(x, y) for x, y in board.keys() if board[(x, y)] == word[0]]), + word, + board + )) From fd1c676bfeabad0898868061a62f3e991e3d7bf0 Mon Sep 17 00:00:00 2001 From: Cole Fuerth Date: Thu, 1 Dec 2022 17:41:06 -0500 Subject: [PATCH 04/12] done optimizing python --- sample_input.txt | 2 +- solution.py | 45 ++++++++++++++++++++++++++++----------------- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/sample_input.txt b/sample_input.txt index a70a1db..842191f 100644 --- a/sample_input.txt +++ b/sample_input.txt @@ -1,4 +1,4 @@ A B C E S F C S A D E E -ABCB \ No newline at end of file +SEE diff --git a/solution.py b/solution.py index ffc1e7c..4435b2c 100644 --- a/solution.py +++ b/solution.py @@ -1,11 +1,12 @@ -#/usr/bin/python3 +# /usr/bin/python3 from itertools import product -def solve(points:set, s:str, grid:dict, path:set=None) -> bool: + +def search(points: set, s: str, board: dict, path: set = None) -> bool: # points is a list of tuples (x, y) for points to try to connect to the first character of s # s is the string to connect, check the list of points to see if they can be connected to form s - # grid is the grid of characters + # board is the board of characters # path is a list of points that have been used to connect to s so far # return True if s can be connected, False otherwise if path is None: @@ -13,17 +14,30 @@ def solve(points:set, s:str, grid:dict, path:set=None) -> bool: if len(s) == 0: return True for p in points: - if p in path: - continue - if s[0] == grid[p]: + if s[0] == board[p]: path.add(p) - # list of points left, right, up, down from p that are in the grid keyset - adj = set([(p[0] + 1, p[1]), (p[0] - 1, p[1]), (p[0], p[1] + 1), (p[0], p[1] - 1)]).intersection(grid.keys()) - if solve(adj, s[1:], grid, path): + # list of points left, right, up, down from p that are in the board keyset + adj = set([(p[0] + 1, p[1]), (p[0] - 1, p[1]), (p[0], p[1] + 1), + (p[0], p[1] - 1)]).intersection(board.keys()).difference(path) + if search(adj, s[1:], board, path): return True path.remove(p) return False + +def exist(board: list[list[str]], word: str) -> bool: + # convert board to a dictionary of (x, y) -> character + board = {(x, y): board[x][y] for x, y in product( + range(len(board)), range(len(board[0])))} + + # you take the input, and see if for each character, you can follow a path from character to character. The same character cannot be used more than once + return search( + set(board.keys()), + word, + board + ) + + if __name__ == '__main__': # assume input comes from stdin @@ -36,6 +50,7 @@ def solve(points:set, s:str, grid:dict, path:set=None) -> bool: # A D E E # word # ``` + board = [] word = None while (True): @@ -44,12 +59,8 @@ def solve(points:set, s:str, grid:dict, path:set=None) -> bool: word = line[0] break board.append(line) - # convert board to a dictionary of (x, y) -> character - board = {(x, y): board[x][y] for x, y in product(range(len(board)), range(len(board[0])))} - # you take the input, and see if for each character, you can follow a path from character to character. The same character cannot be used more than once - print(solve( - set([(x, y) for x, y in board.keys() if board[(x, y)] == word[0]]), - word, - board - )) + print(board) + print(word) + + print(exist(board, word)) From 380ab55ac26523de96f96cc5d2c3fd28630521a0 Mon Sep 17 00:00:00 2001 From: Cole Fuerth Date: Thu, 1 Dec 2022 17:50:45 -0500 Subject: [PATCH 05/12] complete the readme --- .github/pull_request_template.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index fb9aa3a..30dd684 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -2,15 +2,24 @@ PLEASE FILL IN THE FOLLOWING! +> ok + ## Full Name + Cole Fuerth ## UWindsor Email + fuert11g@uwindsor.ca ## Application Form + - [x] I certify I have submitted the [application form](https://forms.office.com/r/R4A1JyB3Xf) ## Briefly explain how your solution works and how to run it -My solution... +My solution uses dfs to find the result. The first recursive call to `search()` includes the entire array as the possible set of starting points. For each call to `search()`, it trims the list to the points that match the first character of the word, then generates a valid list of adjacent points that have not been visited yet, and makes a recursive call to `search()` with the adjacent points, the word with the current character popped off, and the updated points visited so far. + +On **leetcode** (how I assume you are testing), this solution uses python3. You copy the body of the evaluate() function into exist() in leetcode, and copy my `import`s and `search()` function to the top of the script. + +**Locally**, I am testing using `python3 solution.py < sample_input.txt`, where sample_input.txt contains the input. Input is read in on `stdin`, the way it is formatted in the problem statement. From 8db011264b98c624538ecf6dfff3e7fe2eaef362 Mon Sep 17 00:00:00 2001 From: Cole Fuerth Date: Fri, 2 Dec 2022 05:04:18 -0500 Subject: [PATCH 06/12] start working on solution in C++ --- .vscode/settings.json | 21 +++++++ Makefile | 11 ++++ solution | Bin 0 -> 127336 bytes solution.cpp | 141 ++++++++++++++++++++++++++++++++++++++++++ solution.py | 20 +++--- submissionCode.cpp | 106 +++++++++++++++++++++++++++++++ 6 files changed, 289 insertions(+), 10 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 Makefile create mode 100755 solution create mode 100644 solution.cpp create mode 100644 submissionCode.cpp diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..f589c77 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,21 @@ +{ + "files.associations": { + "*.c": "c", + "*.lex": "lex", + "*.pl": "prolog", + "*.rkt": "racket", + "deque": "cpp", + "string": "cpp", + "vector": "cpp", + "unordered_set": "cpp", + "unordered_map": "cpp", + "map": "cpp", + "ostream": "cpp", + "array": "cpp", + "string_view": "cpp", + "initializer_list": "cpp", + "set": "cpp", + "*.tcc": "cpp", + "utility": "cpp" + } +} \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7851363 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ + +all: build run + +build: + g++ -o solution solution.cpp -Wall -Wextra + +run: build + /usr/bin/time -v ./solution < sample_input.txt + +clean: + rm -f solution \ No newline at end of file diff --git a/solution b/solution new file mode 100755 index 0000000000000000000000000000000000000000..ee6503c805f739bafeebf1e5e8f03eb955ede1dd GIT binary patch literal 127336 zcmeFadwf;J)&IW}5{MKbD%z;1M@2+M3y6q_8ZNx7M`Z$L>g-*;l$!QHg zhd(!87#p);@^djyC!JQHlq-;nG}uX#9T(l&1*Kfnug_7M^IIjQsU6a>E#dC%>5bzvG0I@!TyXnonfZFsD4;t+U=t5CCB+r+0^m9dwr*D;@M?Wr_Y&p_Pjp5&+gsp zoY^zZ>8Vr@y`&EDsY@>(>Ci28LNnr2UvxBS;a}SG@y0JY_uaPjjoHs$IKTJoBY(5| zHCKkzDS6~4v|OLbpXAZ)zeimQO@0lN-kf&yigp8aD)s+oBH+kWvU433rK7iw zpq~^$zafJD3<{@{|66oPN8c4eUxbm;x--?i586p245po`m(EqRq zdOSkTNz@zTFZ{bILe7{7IS)kG`DYPwBsRptm6EFoKZ2>ahfy{Dv+{|fd$ z!a3e4jG-{Ud<~96JeyrUal%<=Net`ll$KsQZN~J{+2!MAm6w(}r9(yxEuA=N)}(8v z&Mu!cYsAojWizHv8ZmBs*(A+N&$)VddD-kC!^?a0m@sABtkUvXVFmGOu9zA;MY~-3c{n{ZD zQiTm4ClY&?O`3jf`IMr$lpkK+vwLZ2`IK2RZYb5{(n+&s&6rj4T_s%=7}%p|*msB1 zva2uu=9NvIS2Ru4L+c_nO4G&>r6ao2%JWNyeK)$+;k`<+!-yWGMMX-x8D+DJ#;Yr7 z=%5~^iM=LGpIDZz_H@QI757%{{co&0dk*d~t7w{TcFzk+hmEH@Crv7yI(_yeTx8tz ziKVk9jUQJwZu*2t<4fqJK3x>^av2!C3@(EMOIyZf1R z-{}&Ada90$_Jc^r(yrS}+u@szFFgjP-yj`H-9f7$*=_5rNy-R1*Eb!Eo|9T$;P(># zXVE?HpehEg?>3%0l}?^9ivf%SMRc%ss^R6mCd`;qE*k$A9^PyA)SD)Gt!Hd`{T$GC z;-mxk8gca62@^_ZOBn6pl#ZN!!&GDqn>2gQv`G?VC%EyI&^qCVr4y$7uypdcsb$8) z#+6T+Hrp=g3q%9QzCMZuEH+8ym>A-=d=bqEuxwLr5fPtkw z&*|k|^*rZ1eLZRvIeMMbvxhTq)TsUghLrX==Ukg3vp}}`uNA9ReU+`Qa#^Li6c<~o z9Fo$xb3mp6vFJ)z24++Bl!fu^rCv(BRH z9@q4(7G3%%XR&=v^(kj1BkK-J&1i62U$e-ChS4T6A-?p-ROq zy6iLEUx`IO+9iUcEc!7PeXK?Qwnd*}(F-j4OpAW3MW1KUkF)3tE&A~meThYP&v=Br z%%Y!QfkPHJWP$&`S>PWXPW(^2VozSYGWUO494EfGt~|S?AzraL?^V^5 zmh*1=+Hv-_oK^vJILVRxQ-rg3*PmNjT9&D_92o4~^|qImgMz)gUh&d$K(Ke$FTAuI z4D8+YsF#)lfxWx#@zQdDvUk_5URpNqdv{&$rR6|i@2+uPS`GsC?z+ND%K^aNUH!eZ zZ2b4`>fxnj!@qae$zEDE`g?aB;iYARzjs%bmzItF-d&%4?Y37o^t9hg%SN8|duiFg z(|#{48+Y38rDelT`@OVm)M>w$mJK@X_tLU4r~O`9HsrM5OUp)__IqjBfYW|2EgNsz z@1v0T$6xvMlK3n8TE(-r#NYn9ydwhs@*gcA zucc|S@>{pO#J7bPiMu&-&Keo7xaeMTI`PC`%G<>&FWN#Pc^H15oJg?PlKT~PWR0P$ zSHG0sbpuSf7)iPQSM|TL|H%F$hR1K+lSkl;CtljeK#M0{XjX7vQbAP{P@GuY2uzGu z=A0&nPw_<2)*f~7%EdZseez<-yST2y^14NJDOV=7Uls<)U}={X=_|pyPDWXo_tXY5d#UGR*@A%!g$rF9E-FV zQl(Ro%t|aSRBfr!uvj%I@m@UfrU+W7O1kaT;+5`?D~8v;-l;X5s%xk_Kn*8G)zCj! z!**I&S(syK>{b3NX?)@p`XkT=)qq>0#DAzQrn;Ag&N1SBbv^M{XApl%l=uoQUMYn5 z=a}oTzMK4rsV<(_5p;6MN%{_eEHqHmUC7`s4{(DK~k!5+h1!ic)F;?eLV+4p*NXpi~g0 zT*{G(B1*YUJW)v#rCiFVRF_7nzbZ==t%_IbpyX4g$=dK`OG|XS#aaH;q*tGtbtk?Zo^hJC?8CmrAIpWkc#oS3QH8|fEgkzGGUYpo-}K!u`s z<hyrYzJzEA?#K{iQ{ty;Xwc<#$A2T3-V zWQ|TbCPJMobyqF!Zj$$stY18qywXjT>WT(eF4k4mCx0wna>1(|?j>Y*So8=><@&`F zz3g(8c-0h>9@WK^2j3$lY2q&f65>c8U`RpKkcv$teO_f>yihUj)3A7n&o9s;UQyh} z>UwbaN~KejCT)~xH4;a#7F9i(MuQ$&gJoI+4U1R!8r(1Zs{0hBYOyw`(%>~19o8SU zBtLD#-c$3&;;~}!s{1q)Ei`wV;{0g(45WO6l3`5%|o^mu0S{mi>SUY`N)bxdmdqx+}YTNM=dXeM!Go z#t-S+3rUsv6`QgW`C3qgOcUZeyB4yF(SE0B;z+wLf+kL7e0x3nD1s8Eu1~IEO;*2n z3b~Y@KP*?cYl#5tpM3#(Ufw_+x8O9TmvV#3`vRquMR!QS1ZsOddZaF({nT|9mC`ou z3m+TzOegKG6lp!lZEV>iU5U{tB^*i^n^mX=XYD#1gVZlB^BON#R^zMxVK+Xh8t(;& zY1(_m=_~IG6x8ki+_c|zvktn99zm`NR7#uReE684tqSYA>Lu``5q)bq(Wg+fvLIdd zVQzM>C;o|dRXX(QN@ABgiHxpLhRE9Wg)+i@$^)v3>dbiTx0m)*z0@Ggswy*P9W`|4 z)ZtsJV3=9&Jt|DR%E*<%%+0E#_O{XN=q*Pa%7&k$JDe}pTqTu)&uXr!l4MLLr6Lh~ z1WBff%ArYbX6mr$9!$3D4*qB6qTT0vlaf~Eh0g*rmDXyDmh29XUveyAX;rPcu2#qD zq^s4PI=^FANVtuy?2-b%bv5?7;Gt8-G58b&-iy1&{+{9QSrNa6XgX7*)~ldu>e*!KNn$)Cs$^xA%2)ZY3YM}q|6mC1 zuDVavS9MbX>)+zUrsP@{{#%M_sNfg;J;&ek{H^2f1*x!x3K!}MB@~znUo{oppet0# z$|{ww@?jk^QY!3jD!fotxSk4r$zLshzvAyj{(dbLuBXCfx9~_&U?{B7p%HU75nS1%QAqQV-HP`|j=uW*a0u(PgEB`d2` zzRHIsUz!T%nF^D7)|H+elGxJ!Wn;8@Bl0y_SXbRA$>PL6ixd3+v*N^;cm&SUpfbH3 zPq1FBPrj$JE_O@)TqPe?E_3Uv%d}Uk)CI4Ww~trs#*02koUhxqapMj zopk%~Hl1{RXtqweK0Hw;-Jvs5CtZbF|6L@jrchtA=w5Z++B;=T*C(e2^B$*?=RG3a zs*5&!!U@7J|0Z^1xtDtp$#`N*Jn?SwLx}Z@w<3%7Ih7B~m1mgx%!pP=%q1<-Y@d)du**jR^tRTs4q#cx5!3RP{^ z?mJQcmR(x?s*84Vl{`tYMT@Lm7pj*?wWo{263|ss` zh*kG#!4y;gOUR5shQ@&7O*8ynxE;tnG}|`rQsgHV>`%4&CRiYs+(!FTu9`&-M?IRi8XwDd~CWa2ml1WkD^j zUt?<^XCjp&Yp4X43bCyyi8c+I#2Qhjo8na?`Gc;rb%wmCZca}(TVKhh*!9T~st6O` z&>BdM=B#$CDpB61R>tSoPev5_2WcOX{sE$%|JFHL9yK-g6}&qO$7H z%3x3a<1f)YNjF}mi|&&yy~e$k7Lgvo!CaTHG%KSP(adPq^g0jFOd%|X|79hP)<5RVr^#s6#tODL4C5F(ph!( zQR-6maU-{4_&Q^FP&z{y{zdVJN|Kf0GuGCSA#~Huw7s6v0$X#@U>^OQt_65ZcUq6L z&uK{U7(BUhsJKUy(QLf7bXu2a`bb>DwT$t^ByuTCI}$@1iW5b3#R)lt_3t3znaTF* zEE-c(Vv%=u6p5{N*A$VULjltF{dX zkX~lxUFcpL&F=qKX3fTuKa*xJioAeka$4`&;jyr0?h2)n=%lR6O;fgp4eEv|VrqZB zM*rd+p50{4TY=e)qS7f1@vORd7Db!5*Sgh?no+g*0%f3gO*c-|L?k1(KKTXxEr-vQ zGIi7^KUT?C^yqPK{Cy-u6H^K89d&5WO+MbFhILo#ctv>?ZT6Kw2kk*-9VoTD$(pIs z!4l+DajF>~$`Q^woAV8#R$x|rnulTRS+!oLnNb6?>YI@5SykSL(gCeL`L!w%o>kkj zmXTw-(5yN}&#F3V{^2mGTuxsxsEYJQiutMn6YQ}FV&Y1jU~6xd(mLjJi_msS} zm2rYy_W=`Z2mWU!STCvt{7R;UW;`mghwNzZdvwSU4VE$rtmv7h9=$qSZmrHT&pv^E zT%d-XOewNp;=U}-LBEFkaXw_bA7@H2W3)S!h;TpN4>e6crdu7|r-TJMZ>=Jw>AWv* z^g3^is@LzlY)Olc2UbV9$+3U(y33o}#X^1buq6QCLfo=7Q!n$8JrC(|%yf%>+Siim zSVwZ#C$Ezm|LRVmN*1Z)D;N{UbcgnQh`UeJOEfPCydgsLNvhJ1bp*p+KR>~2zIKPw zxld>fr$@QOJL=x9D$}vNGVX;zy;S&(FipmB)Mc$ryl7$A+sK+JGH(d+|2MW;$(342GwYVXR_C4fLaT%rZb;t;RzA`sz5es$6-UUsEiBLXk%~HG z*C)GE(uyF#xx$V_r>TtI7zz8yl|eZN9f=C0fvQC)GY%niUB%`Cdq#705~J(2_@ybj zh@J3zcP;L&$5r^hFeSIPf}RiUHcI{WSa4;kZLY*^s>rv`GUO4cialegyq3yqSh7~L zWL?FQb%ot&I!vq(drMDo9|KvdBzYD|J^NFzKG{|!x4^CCZib2yZl0p8P`65^LF#t3 z4yh_ItL6VAm2%$xy|1Iauy= zt6X@=^;s~QvT76|jJI_bJ1k)szU*JzQA(xZi3cUUj}nOstmw+#CRR)qHW zA@^W%2O>INZu_*1q(It4HMJ+JSkUB@f7jKgtD(7hQw z==Nw2IzbPrXb&1B8B#syFXHAArz#I`4|os`6q7#07R>|$aUQTf*+#lU&T7>uoAe5u zhP(LDUwkhf@I7n$jZ#ev1ZFN4Q0KjC4$Wa=yM+ZOV~0sr&lU(?N5#*U~+6ir4MxWtsC_El3&a zbYXtmHcq8JWsxIEZgW2^dG(Q^wGt}9k!tb5zyYj|=ry<`Eafm;rLb%%w5LL@PtMYT zLmwfj6Gj=GD*LrEShXi^HKY+jk}&MeaVl01RPL^)ypy%-H=0v`(4uS1+u`w(uf~sx zQT55zoemH$qvPXysv%MF@g3bv8Hr6;#2s0W$xh{)#K%y4zZbFLs2Ygp2OrGfCSZ=!!{e2<7=uj7N^6Uy~IEpS>vDAT=|y2?9M8_4oiJ7=?a;B#s*B^|fVc-eZ1 z79{;>`OVjUB^)7JYrj8=NOkg4Ep@hsE0cR*?e`m%$6x!!)d4(;akIf+`z2J-;1rg2 z?Khg@DQmwT>bO#c@jBDm(fY);E^_U6>>D!A2iAU{AUipZlO?@Ad^LF=*JkbaAeYH6 zq)d42Cy})e!;R4#y!oKl%#c~|dWKTTr{#%0F%;`8wIn7Av7N3@_SD8=lF@oGgJMbL^#xN{3?tb^7xU3ahEf2s@ed?i`grbhv(kZkKGwEuV_X zM4GaiWt8iHhMTE?cC}Qj_7}mO;MQ%SouKWb5;9x?=Oe&6ArgBQNYw~UO3SW=e=vKh zp+Pw+0$M8wv%Zv9AvW>soP7=&J<^UxrnSECWd0xSr}lG@XN{@fsp&)xQmUo#FUm1r zcuc*bryS{fX_P81jdx;j`K7ea6k1a#Z$)A5O-4Y_fs?V5-xg7z4n`wF_n#& zd$5el=&6pa@W%5yCV#=7p1(f$Oq?*!spv*Vg`#SNK9A=O+2=8?1auJF1_>s3l*5+{!#f)?2RkrE^TZWyJdM%w{B5 z{+KcX7@lhBWCp|*k(d=eWpLvV(O{1BIo_e78`o-_J|U$N45`X75?@r%n5p86D9uPy zxf)e26+eb6)3V}K%WcX?W0UbL$qrGqT}e4pNzq4Jl4*`OCe_v_FZDzWP`kQ7ggJ;= zlNg~ar&Rk6!t9<1uL8npyQk1)KkMs&?OlFqpZ^^r*fqI1)AqT%!bZOb?#SpJK8|5K z!dqfm;|N!2NARMpu?3#=4g8>1^_99UWZmKUrhc(RNeTMJEh&ESqROTG;ykZYvy~@E zBV{LM-)E}oC}$N1=_SW|0{;)Zq*bbyFd(!asX0fEzdXC!J&TW=LSa8@_~TGcGR)vR zLX=f&9-2%E^`yE?%z;()%h)WTnu|D{>cXS`gUsrKvGsUo}?$MCdLmVm;=NwbRH5j4l_Yk}Ap#aP^5$4P z@judo^F@qwZpG&A>QK)+A(sB1LhaSmzKV#Naw1w)1i3z0pj?8DntC!u&)c8K)`Exh z<(*LX@IZ6=N^XueFC=?46(hYqd7%*X(ePj;O`_=v2_rIze31OzF0~~ObOdX=^WE}a zDqC!d*B5PN=(537r+zeC?Ie}Yng=U(t(8}mDo3u+MOAP0pvqm#6O3EE#6m)MRjZ=l8aK^GL z&(+1;JXvZaqt@w4t&n-vC6#$5Q(>LxeyTi4;=YmF&9{nouIXClUu=yjq-(ub+Eq2O z7VGgR$|>vBtG+RLrmMCGtoILO?7C9Xed{e0!MsEo=*7d8njIEpM;P!trH$t|e)o1# z(xSSzrz&O?d_%flJj(qjA z%0X^c@P?0#Cs!5y%dB$#spJRuD+S2)W513)g^YfJ$sC*tw@3^P90ke#u3|x*GiM-{ zAQw+U$a`ZK6xEjZpa-_PMxDbtT*svv$#f}!sF=6xbr1Z92g>Myz`$No^nsFC70>Ii zUaqOTa!w6pd-24qVpSG)Wg8}QEESh@B})y)Z!*m*RX!l6{PvBH+~j#LE7KK*?_K2k zGecm-^%vz>0n#y8F0hJ{I39@q_WbHbQ2cGqGJD#y?kCkTD2OCAw1sT-$xoH97uE7o zi?pvsV&!mkkx(I40+%x6AI+esl=py?J3q}sVoQpiUAW*`hZ9+o?INC@-OXnLbfIHO zNo~7VE3^8Wn<_$%Dma3yN|Cp;A{-6}P8Ra806liHi4@l}dHhgAKhP%G+OWvsQ<~P6B(>+^_ zqG`9R!k}LwjL=Z;gP}}#OiR5tI={9g4Jlrl^7zUrH?&Y2GUwJT9ijO8jl_l z7&Nc(C|c^Ec^APoV(=1os+Va=O>pgWS27@|S`RC7t6|kdfj_+%IjoxKMOTUI^ss6S z+xGomE8CU?R}W?nyHAadgdAY&yBII3&?!%x;{~#UPKwU!q3RQgeR2oPIuEgW>7e>U z<)`mLYb`xSoAoXZr2=<>rHs8SHl56Etb&jj7mSq+lT`G z?Kgj}O!c_bof9I|ZD83ZaRaS#NS=wAcc`)pEU0lhEb5>a zge#~|1*NkUTNZ@N{HVX5XSZ;%Bi&3l@7FSSzlgQGqI=bg$824^iEgtlcY-b_)1t2A z3R7Nv>&7taz*-dB8qVC=WQJZR4)HaQkdu%6LzmId2|3HuEh zVTqzuOo-L2<3Mjh>}t(OyNguBt@48M@lu}zVYQ7?aXL>(sbc;twY&WmTGNc<{t3Mo zSPuH(tE(SD7#1aX>Q;sY%^g{5Pfq$7Cs_5#|ItsOG@=H7-jb^3KT0#14k)dZ{V`h6 zdHvB$m3&IuC`n2FyeFIH>XOZn=mu5t`?_Rc(T5~ivM5Q#T7-?Dg2q}@-@vt~dyM_?zU#$zQJapKeo+oc@9m!|6I>iNt_AJO9SI1^^~jDH_yjvZVs8}6un3EPPuNBnZ-S=$#lwfgxpJWz)tvu`JY8hkq=qGmIWx8DGTlL+a$TaUh-7`TmDF`XQDcV(d^C(oPI*qV-r{s98IzL;Jr` zHc&{<;HmxjZ!!k^Fe>LqvJEpmpY`AN{C{+Hz7_nv$~WtIqmAA3?<)m^<9z@<;@jaH z^!yjH4>H}nP6P*g{+VrF&(A2L=RbKeea~;I{%?AIEfxN^J^u)0{T62!$!o|M?0Fe& zzGJ02)eE5#rthqkqT8GQ7whs9|BC6oU34Xn^!?oR2XI&n3#`37cpK5RsDFjIZu=il9aAbzQshO z*JuR4`eZ*;7@BAk^ za;a}5%Lgwl&&V)&bMM_hE_j@c7nKpqf&=-+pUFV>tYys@_8Euof3ZN_I;NRkc#UPY z)q~+#OI4na4h#hWLTr6o+{ym2!_~2peqw9?xm=9jJ8ocrN8;TksywSL!`Qd?R>|=byh(E5>y9 zc#c_$}y-6okeTB;`Zd2Bbb+`xKtLC-$^p09p zFDI(p88zR@$W31PIPKO)VX1ynQD-0Jr|WZid53y(TRPqD`ziD&<2uiRlBghgtBXeG(VZ zf8HY6*~|VDWXy!3$Awthjvkq!QAvRnj^;9Cuyb=*;3umBF~qm#KHVb}V9BtF=U)PG zC~dFaDHe76QTHkhD^X8yAFy||C!K{l2lhIoKEc5BEgtS~+^K-ps%~$~ZrdCQd?~7= zo)F0}v07(huTKd}S7HxW?&EpW9_1Ozo8-ID2jxxri(PU!5b&lJL|NVxuHA0iaurt9 zaYwqg>96T9L+YbVdyAkqoGkF={=iT-D#;hth`8aS@0-PhX`JWjN9;~;r!wDg`pf** zCWVDS9SZ@f1l7#`E?tv6hHBY!s!yEj`F*c4r&t&5>ysamWM*f6Htj9U;o@M7~mO-Psfi_CY((5V97rjgkI5b)a`BLIv)5>XDlx*KI5HjU?+lwcMqI z*KJ8wGqkNK9Qj8-3_Y}NJ9zEoqXqP+w%}s#_yp~hhg|ilnzmBTfp>~BvfliaTUM50 zit?oL5C0svyQg<>U$}Z@s@^8v?ejKx;z0D}ZDLmSr8dX9Z(e3od3@9#+sdun7_6d8 zhM1H#x(1)gER&^U8fR{LDB#R)^jA}8ee%QC#3ZtSp+Ra_J6R|u%1gT@|03nNM{?ViW({=sp5}5C<2kDOd*RiMV_v;W00#SgQNynC0#LyH#3DJLX%Yg?Oh_zi$|Bs zlXH3@Jd(?Uibuz(GAZ%s5-IQZN2qrH?oAs}UAtNzRyS^y?)i9Nje){an=dsrczF4B z-z(o){ejqAy*X-W^i6ggWzUKPeSUb^?*luI-!nxHNq9SsJjL~P9AkL5)!K2q-X?X& zF@{57f5)+Kh0?Ww+6X+l&;P}X5?g=b?>P2zZFU@4;tvr!j(pcT($Q0>C1f{mba2~E zJrELQ^FEwZdi%B>N|5JO2WiEwvTy71jI>Q#F$cp~`?f!_@3E}7i5-JJPHYh6ua{ks z@=|P4pRDHGHN0=zijKY&`#vBw1@>(haMYi?4eLrP5tdvpmewEI__bU{SW%5eJM6oM zt^^f--!>dCplQUI;J)n@6tTvj*CUKmf5P*qtW|xgjFD^NJ zAa_I`EkBsNW=HcrcSO>TXlqB~X=!~Dwch>gDYHm@A&Vb^uJ3hHBA8M$vAFhGf%UFA zs0oh@I#~UFMDH^l>4n&1@<6wIGqZ|Nlw$V8ZDXw&s!l!p154 z@00`Vce(czsw28r4)j^LsID5Rf4O#7EtZ>Jsa= z9jL3uhYRTe=1yK07B!b2PtUTxs!#q-DbEv~f)z#k3U>byBiel$Q@tgH6Jm3{wp@FU zT7yMRf6pond?_hAJ=X)Q9twC*s?(MS8s$F&;2DFxhI}}3D=Kc4mi?XscWXjiN79-Q zf2@*3bG>Ht-)^~`dSpeVUv2RknA(DaJ`u=%M?zHUMAx`17g7Z{@pq~QTy3+aPIL*8oJHEJmv zZrh;LwuM4)c!rQ0EB?Z1kvxZLriuI2GpY4zmN2fYp3`KxR-YWADhkdN6YdH)U8+&# zpYr-Fo_JkFw1oQ3H%qjU_6!%)wt;~slZNycYjBx3WK2nvQr`->6)mhTks5_TI6+CN zrpW{r3XM$K^GT|5(f#?;w7o-BZrn=oUeU|;cT*c7+Yd?y5oV@u4TPD0HwMB?H@M2X z!(rwusoe`RnIdJN&8czmnSgl@LgANK09$c!`FjC{Z&u6WG;y&mps*Jg4>}4?{2%4D zDa-wLDgzFgG7j~8bGTafNcgj(;59r#ad1(vDPSdUMpIE)OJ%0MVAJf@)X=;;N9wUX zF;y$ns84Q{N0u)rYVPm=FD>$w#*Y)GjqujonYmpl{`ftmV$c)t-p~pw6qB`ePNXi| zm0g!Hb9_-qaztxRB%9ru0@WI#X5d9-n)Vh9e?+Gqo2d!dEM+e&YAEN+b9&aAtk$47 zm#lF)DtkA%Ng`%NQDXuBOBU?jCOQ2*=@U!Do?BnM;3Pf@_#lb%A`&7Smh zxePrd86886ah_QlI!%%i-jdu81K_ly43;s;}+C;^QV9L1ML4a{Z!QC*+1lgQ;L1 z`;FqNX+&%N;?^3Kdkli#f0?riC;2SLqr`~f#HYoHzb606%hkJ25QEEkL*jj*Jx-3| z1TnroS)+QXsL}qS#D1|t#pY4wgxCugUUvljTn)ECri1kS&eVgcd}$%q-^f9bcMda? zc363Jtdvfr8N_G(6-98%%U#6?Yvioe%(Lgb?gmZx^~oC%s~3~X0;5R!_ruSp8VT*O z^luFszq?#1^WU_&`|ZItAE+H4a^C8;W7}^7?fAt%1MOHw(r?E`9w<)RjuK3^6_eFr zG8{7alBYWBQST@;8gJX^&VfVgP=kVMKlzAyh}xU{lk)6qH~0vwPrj^*aAqN6U#%u; zq^S8^~dAY!?c`dL@ajRKqVD*Cw17>TP#@ zaxQ79<(Ub*Xo~O zuGll`8^nU@mz8B!iDp+fNL%b!uyI{57CfSITe0AAj!ykpa1XI5919*GhlvHN(U*1y zVnK5SG(Q&DV>L!Ilr78>kZbb9*Ij;NzlZf!-TRlbnA!nWcUX(H+s{pkN!&szPx4s~J$5CryKJB0F zYZ7_yS>6zf8n?DG8x3WoaMonG2C~+HKODArG7U%hsd#YZIF>wFL zuX;?R9NW2C&Vu>VU$_|dJ~gC$-(jJ|>+t&y*NX^N;&f2i2cnz!;tJ)9Od1~~zxtU9 z&5`dr^iV29JrIAPY;{afPWQgU4R!qEvEi?J?35OW$-Va-<|!qj-*?y~14gzJ`eP>k zS3RB*hPo$%DeIFDs$}SWhsr-%I)=aM(M@#G<{7Hg3Yq8q)yh2H`wnBoUEJsPGrjL{ zvfiAj>1tQR`wpMk)=Trg!v#znDepTx@h7ofNX_$=n$hn&sDE|AGNAXq!!WgGi0ai(56-9R@Uv^*C~A$Ce}#=E2cp(M#9C`)9beDY zzg7nkU*iZB6JDcGJr42WhyUC7+Bu!3Ke;&&UsEQ%^vh!ApZeq($kRt4O_I!0x_Wo? z|INDw{wlbGV#-`kQMEqoDU_7uy;r{%H{IE=D@NQ(>8M&xsZp+_xbs_W_yTNfAZiP4$~pW@@QVzVQp0SM}X>^>CIFF~MuHO72%} z(F>#Gp^ws4m&v=@vi|MkuQ zbwvdt!P>ERXYrPPefcpQe^O4jic;=$gs7t8dXsD()p~Cl=dAI{qvR<8)pqMNDN@dN zhzDUgr$x)bfYQFSPvQjbw11>bm3jl>D%CvCUzM$-GXnS2Eo$bww%@-&nUTKCmZ0L> z&FBfkJ&V<+R@LejXMJ+K#N%{58RaSRd1?#ajL2Dl@|F|R`W&8CF=k6h4=)~ zFr8FS3$GrJVuf2dJ&3q-dPJ(aVhIi!{dnqH*{7uQ5;ntZCv|+djS~ryO~^?a(!V&4 zwEuAw==@uooNt-Y*hYFNw363NV80gr_eR(wFwT%2d^vxY`btBpFMVrnaNfuyw=ge_ z;AIhlpPOTk!IYj&|1#4=gr)W+E%NP)qO|^Q%lJR%2d$>!6G3a zqC1;-Y=Ewlfw*9wdL2%poO}aBrXaO2I02*RAplwl-{W{joLRaMBdr~eN1bfAAu zWF-|{_U$i2+)(6CIc;Z5TB@WQY{YW@Ar`XfkgNt1UqvDr+92~1a@q|t&GOwX!)oLq zbhlO`@<^XmnmEDNH8d)url+}pq2369RygV*4E3F2*ofyj1@+*bVG_Gq>Eq+rTn#HMkVq&TXM}VDSR#0hfTEgVkV1J_+$L z*aytJg?562z7;7YLdkFW=L4Y&h*2iy-1<|cV3J`gbz><6v|M}ynI`C!{yTUzAb zh#m~qfs?@|a5b32cSm-Box!#|A20|!8=MHP0+)c#fz{xDz^!1fMJ+AO;0Q3EkJH=& zb_Z92CEzA-Cb)Ak_61k)tknjv32Xu#o;P#&lu-_H#Nr;X3)qgYj1`03z*%51xEw44H-SsRJ>Xif{hgEtNAQ&F=iu0-*qg^Eo&)=U z?||~J`+f+{1NVX}z|mDLEw$h*un}AY?gQ@!3plWPjN1x*z#ZTy@Sk^MZ?MZf*c<#1 ztOK)oTcrs+5_I@B?R+o>-U}9j&w*pXP2fWC9dH%c@5ht}hk;GtM9|?&*41DPd#w}Jlw z_kfo@g1^KZryT4C-VPRnE5I^v4Y(9M^QYJi{M}=WPp}Jjv_A*)SJUp39p`ee4_F3{ z0^2@8yTKT^61*7P0G5C|z$s7C?o%A628@Akf`wocI2POsE(AMPV>j?runxQcYywL_ z=TyhJ3yguQ!9s97I2L^4DeML|fvdqTYp@$Q4BQD$1amq&&Wm7Ia2ps0JO7+^gCDM? zzrlTA4Vd!`{sJBaHiKt?`KLKfA=n-K9#{fS0%wBr!DZl!U=6qzYyf-m)^amA2+Z$7 zd z?bg$7@Sk83?EFjog{M!i2D^gG!8o`EoC0Ro64$^b;9Brya2xnJxCcD(SNIFF*9fp1 zco$d%cN_ zJGcV;9Gv?S{mr5I7O)W90geUtf(ya?jra>#0@i__zD$3EId$}RH{v4L8Jq_W0#}0* z!JXhDu=Ok04eSJN2FHRs!3V*-v+-B3E10thyMZIXDd0`u5^xh(4Sou41>5n2OcERn z=AGj>qrk4fZf3o zumn7ZCs5~uw}30b<=_Tz4Y&i0zd^k{(FcrycY=lBdT=b*2rdLa1y_NwH|a0%9Iy$D zgU-2*^9wKregGDN9p9on*cDs|4g*(#i@-W?J=g?p2Ay8q2LNN>=myGzcYf4kD2Y^lB2+%o?^#B+HmxG01&O6u*JO*4Od~h}R47eHG2JQs^3Fh=h&)?y1 zU|(<$csn=|TmdcuUj$c!JHgH1F}%^W6C4lbobNb)1UrL&0|$Zmzo$Gn6kG((16PB0 zf}6p0;7;&kFsF~>dRKgPqK7-!%%Fb|5*f}6la;E{i3e1m6#Tfvp!=ioZ9k8Cd5=MQdQa9M|M-H^A?x#YOMXP(>n6sW5FXs~%WdJDn) zL~c2MN$4>tZ+=qOQvT*$*V58fXhrSwZ_gfhc zT{5(%6aABk-|qnY(FfqqKLCH_0r(pZz~7O9FSZ&%`*(l8rA7Xw^h%(3&yszd?op=w({9_-Kq17T}QNHKA76law6BB%#psIl*8YafxjI7>+o6r z`sK&?<=4S)fIr6OXOHmubvyj_^y|qsf0QmS?JmYH`S8C(yK)*B&2GDkX!prko}5lO ztYd%J(sF|>CwscbmnR5k!e=`2Wz5p`h#lm)*ro8(jh7hw?dTzVrWNdJ=~3>>ScQxy z$dj%uQb!&9YWV%Q_S!L9mybbeg1;I5Vw+Dpvv2V0$YH#6DN8Ry>gWuA0Q^z5jO_0z z0m2^y|0ehn*E}7vf9UZi!hbUZe-ZpsrbWl4)$qH)kFxV-_;L7Ac2-Y%!dG_wCyP$E zzb!lG;oIXg)X^3GEg9;NeiFW_S#gJO~gWz|u<(n8GbvDAk z4F1XJ8PM@4t)sMM1h$CJY-xF(>zsXTf~>Y=|4i!|gEyai+sP+3$@!C&&)7xAfP7zN zA9>RGpzx<;;EOIz)FI`SE(@$Wr2i~k@@Uth>y0kst$da)+o`LXJSE8W+LV2%YLMvi zIsC>9{EmmQuAJ4^4$&xb##yrpFr*PaaN??JvUtH?8pJW+mCXZRg# z8H4@uP4LH4K8o*ri@i1csdo8ny(pA6#Ne-lAGPKzgnuvmsCY6K{-O;0h4AOXPiG^k ze--@kbBH&#e%I^v#h}%}pAY{y+r|=$+UapFd3KU#)?C)>;XJ44JW@|yJL2~ZEiJ$1 z+Utw#=Tt?)?+X98dC~n4H~c6&%QpbqQa;MgOW==yA7$ri_?Km8T9K4zdVC}aroE4kMe^l@JGWRWZU;<-%ppoUkLw9n?KI)X9xZ7gfDYv&fRDE zePrfO8JC^O^9Xs=xSV0-vBqVLd~)Ay!;LL1f8g5dYZ-T2eSHerJI?f*qGMaIp z!pK zd}XT%NQsDHF&t*+&Czx!gx_&~^tc#n`04bFiJs_jBISp2o%1EuboDSnP};H@8FBI) z&9%ob_WNox{EOkUS5nB2Se6c7^{A{Bvv>*19Tg z%2SoEgB6FTz;B>@6n_c)I`~m>zS{7k>?r;8I_1Yxea^RTZu^ar(l;0TQXV>_4EFsTE@+{zKW6ADw;~30uGU8k>@G) z(%zWE7g{~kN*O}*l>6-ey0xWcIM-gDY<=JqgCzIg&%CXrv>Ovh>V5gX(o^C zn>-oTzD(}fx37rqZ@HJ>4*tX8x&3Z`Zr@3s+ZRR8t#bc=KKyh(B|6G;0XM-<*B>$X z^1MJ9{BPSj=sBm2XdyD>-!>V`vjCTJ?X~k3->2jmgC+2zbdYBcZik;v2azw&B+Sde zPr|d(_>(h~uZBMwe!BL@r2X(O zho7kr_K>Il?dfHR4cpPUUhvb!KjC+Se>MDWTzh>u!SBOj_>&{#$0$+;e-!*H?edJN z?6@yu8F}u^AfpEUeE5O07?EMld8MB1YtH!Ea~F zXw^yy5L@(t-z^dCFQece51(p$TUlq-^WYzmfxiO2JnItWkG1gsl|lbT_=zY-MaD|%)QGDT9-=CVu^X)sMWIPb2tP2FNgdXFI*2@lW@dZt$aQDeXv-X9;;S&1db7bDYEPik{E9!7qfL zX+A3u!?ca}x>XF2?~@S|+7 z9DWRblnvIw?+ZW52HW9xhaY8w&*4vjpUDOV81r@VMA@JZ{6E8wvcV|$|AZgq)AOXW z?rCZ1Y1?qBZ^ISvkA$Dj=cQ;Z|I2}&&IU2~jqv|N{h4CJe)23wM%0?4(+QmIWZ=v5 zZ_D7b)AoINylw+K5J&oHCH(if&N-dR+`Zj*?`l<*voyD&b@uC$8;-LCS(o42((*m7 zy?ohv110=w__x4M*Iwaog@Q;HZ)d%uy=*6b~oZm6|r|E;wkuk#L@%WaG9oZyI zhd;yN=a$c&tOmBUp%?s@;HPVYoGp!j|1A95?easaS}o0~$jvr;yBNIrRuixy6#kZ62 zSHVx`+rrNyILNd2k?n`SAp<`S|4sN&_L*YJf5+BOhg7}(f&W{|N7<(ue#e#3_Sp*m z6!=m0Ny0xLem}c@^PGrk|LMeS_<(P}YyAG}3gZXxqhd=O{?+iKV#^fx#TocZ;9m?s zUH`{WsoIpEY3rxY64hN7X~Q=1tjJKu9{6{{PZ#H{Ni}0i7k#6umgdb&tV)#w) zqkOCk{wMIGd~7NF{qUn~xE8*=|50q)AbX%U$83Xt+{4l3_rRC;MxtUwyEB-N;YaD; z4SoUqDE*7!%ljx%`jx@I68?<={q^Qn?7tMgd@ww+{qP@!PdN8|)I9&9`XByk_!rrH z>nwQ>{8!*dwXYqFZ5itC27hCQ^2PAC!jG~~8T|L)A8qSr?qkKEErtIU{7gPxL!M5L zMBAtVetY;)h#Duo;LCeMal0MX8hQl$I`~oJq#XW6_))QNIs7-_ z53uFm=*OaU@SEZHu=#SckF@x~cKF#pjh+iWhyPE?6ApYovSM9FCgHE(N9o@S{(kuB z_Nq*?&RT4I7WF^ObEFyKl~Trqpn|moGwqOaLTdMX86D5I_INyejax%|0}<)_}Pv#VO4Zn zrog{41AhtpIQ*#jyBdB!_)&ef75*UjsO;-$&LU!vlJHC5Pq+Dc{!l$H_GrhTd5}C& z{oW1!3iwev7Q|dEO__MqAJ97nGqzMh*P=kMb|t+I;aV*@Qz= z{!gAAnuCJJI@=DC*7D5+bqF$SHr)a>zw_E zrP`*{?}yRIS`{Hn`e{D=74QqWwqt~Q4`C(zTKHGkd~>r%%5Q+b3qC6O<*jEDcEJA^ z{HXbGKm3lXqwU#=0NWaVy7Doq><7Oy{7h%+W687T$>=sLguerRI(thSSHa&7zmV&6 zHmZaFc?S7S@K38w-^Q58WU~G?{ONM-#_3R8=uDn*5i-Olq@PB>KPd~J_`HoT$BdU& zhx_;4W+Lm-r=nxbGWdhx%UOe`k9E#a1Ahwq5}R+If5Be?|5BTekIVEa_H2e8 z+VZVuCz|1(0)L>*zsVo7`MpppL;3FT&(FXwfqw@4sD0Q>_!q;EI%`-4zgL8OSzF|x zzr5o-nd_XDxxNi0j#l@f&pFZ%<{CV{A6rR9D}qE{&(RA;z(#N>~y~4+(4dmV@YK6gFh91rr0@_JkOJdqeEX0%TE`=Ul&n_ z*m)KFuY2m}1HE{dtsjt%!LNgV*10V$$8zoQ^|7l^oI(7_d$LogW0DXCx6i*jdr13& zyIK{sk5%OqwePw#cToH8x3`YB?^Ds{()NYZ+xO|;zI*@nT?e#}4QO95pnd*;_IXY| zMZ5Lkeiw2Wb>6R~CF{&TW?{t#TKz2h^|sC@xz|3|)@f;dd)9+(ouB9BE^h1mJujE* zkK0m=+{b>J^^=^{?VQzZe&1?SJLjk0%6+<>^TgqrIpEf;+`qJQ_Gab2(a!lOJNJcl z&h}Qh54Uq(%gJ5b&RL(E`?qg73tQ(t`7P(AHo3PS?tIYZyg8qTMws& zRMEaC(x#sNK(@0!Ynq}6)%`PE{$1dGSvUcl!)E8+Z# zPZlQ>D4W+ex4&~W{6oJ(7C2;qLl&?sF!nT^_&alo{9-0;LaG~DJse`fh|8aB(wxfZ zUrfW{Cb{(&`a;c%T+ZvHOY%sD`pJAIKXtzbTw?e#=gLpc66E*A*ZMZ_s#ZE}s&$fV zbL7`rgR|A}*}<#dmnP%4Oj@n;xIWsXT`TyfY?&oyxbxw~nG(Au(ZK4&UxWIKFD@Q9Q+v$^*-pU!3mY(Cx zPfO2r-0^9NcUmzz-EkSDxADerke=tbejTJA=D6b_NN?-7<1R@5mgA1kAf0Fxvnl$z zm2l%(n3R!#?JY+8E0vrsn4pGB`#6t)ifkK}5_2mai+YnN(86m#QkkY3=V8}F@nNY{;z!Tdz;klzZw6(7heOiOp8 zyDvqw&T&3#@hSRB=9O%AJ@QR7`zK*h=uIK|$%gLEV{RF?UQQPJl$@;X<63F3qNmz{ z{fd(B&X2Afxo4P_#-1ynr_=vuD*usAUL637~|6W}m>9nmAs!#t= zT_5jU5z_xN=wgS*%=|r63h|R{LU-qNcm9=n(&@P#MiyU->6gZT(&gW*6i)TeQ*V}f zQ^(i4N`9(eH7PmAr1;@yh936YoNUoE)enz@ehTevxL-A2MwI#uGxX*2b=sYG?>6+Z zi#5HU2Im<=e{X>%sB;-E|6%AIr)at>=Un2T)Y~Vn=?0vu4E>1(=XKET*ZVg^opNo!o!CCw4v`Cq6udk`rC$nrP1?bL+`{oNaP%My(YN& zk1_N_wWhmvd)&~Af1v5E{vR27fw6N>BfmEbFp=L{J#ff(xeR@xp|8JN6Wshy8Ty8w zYC0zu>L>q@tjLKE*6HUB{R|dZO1?3SD}SV+KM|_;dFXCij0gqUdFkn$po{!7uhO|) zyUF(ygnsW`n(nSs*BW~7RhlmMjpWydg`VWU-`H)uCOg*|`q-N^VX>jFHuUw^X@aZs zUk&~J+cZ6H@?XTlR^(3~pb4iM`qhShn*=C+oT#YZBZgjQ0>d$ezQ@q-cvchC`5>1= zSSXA9!6ttPlmAXbZ~nd}xa;R<487zsO?T}kAwc9@d5fmI{#It_J*Q~8+g^^KRQ|rt z1oL-1T+?gs3Fg1i(AN}d`WYIWXAQl}a7}Ra|IE;fP5-+24`U(`J&zfx^Sgd^uAyIZ zji$T)In2(Kapz|iO2tur2F@^3NpEunGUjtnCI*H7t; zu3z;x^nPaCVHWk9W9Wk})oHhX?=|!;MjuzsYi|DQbbb?toRe8{Nxko_)%3|4oExS( zPE2;Mq5d6g@;90OQui(?^NgW)sn7zt899xH{_bO%;O4)8fhP4f8b8D=>URh9Bdm2J zVPF03H~I5d>hxKLo;38o7=LivE03&-{EtmsI^X0kG4vzHXo6eseTM$wAWe7Wyb9gT zV?-#}W%6${HzZ+#3sJTA%% zeZO&VcYaxH=vU6r@=Z0)^NOx%_W$34p3V*@u*6sWV#bS`=L$nFpQWX^{rIk-&out# z`c?ZAw47OY==`pIt}^stcWHW0qtu;-UcEvSdKmhfhJL3R*Y3Fc+R(es)ERMC^&5f$ zqW=^#e%*L-kD-UxdoLLJ4@2#J+tADJ({e8|@`n+KME<@?O>pa7ZRlSbeJHMetz$-? zg*xr_*C6OeBIjqOq4I4!`3;Hb{F{qa(ix_~c@nzY7lx$Z@6bh`xh5lFP5nmWs6v15 zDV^?b=x-Q$-uE@Z?U#0^=={@7fOOl{)6g4?;%@%=hJM|HTF&>3{5K8#MB|5j4E-xZ z?_v7UZOg@{>Uz(gpfj3q;H)w9Q*YGt^NgGi4Shp}Cb)8r>8$0fF%5O+i~fdw%s`#r zwf`jOZdoH*!7`KoIx~LVetf~u_fFBdUHiOe=+8~mbT|LWr)hl_-m2-Qdgp#a50BH$ zhCa{q%bB{EdhYy)?Bks9`O+6A|MAs2qj7iVGedvf*v<9x z^H10L!|Smd4gKQ_v;f!6Pa67hW?a+V>i4dp?=bTkN%iZ}Rm&eXMyFl7O*8blk7_#M zUHzUi^s*o5v}>Oa4E?xen%-W6a|wY|+Pm%%O<;MTes>#syNh+&ZSNlpeb_=xcl);o z6^Wc-H*30E@AnOTuo-u*9qu&rb!Hr??+H-!943Nv{x%P~8mG@{`K}#aHS~R^y(|ON z?_Y-A+YFSchJH1HQRM7cq6zM}TWaXx{(8~S!|OEXY%Qm?8PI)={K~ec}QLK{Pr(&?vqWSE6&yQ9OH+^e9o(e-fFGR=+^ab zLoZ&W>8`((_0n>-UZ?3-8u`x~`X@gQ%4u~s`e&z}({{j6qUU2qA6NcdL*HJggw zzi;R-KBx(sk*l6fyFz}_lznQKH#~6C0p?3-S!#@nY_C}rY0+YWt7a}Ko z-gTp)hvUNsh92IJA4Yv5XWo-qaG{ZZj-f9w{(#xl@B4=S*!OjMsG;9z=;3wmy@npP z+iQm2#{~ErjGX<3eue3;Qw{wJ96wET~$Uw-a*EHU)g@746U21mX*FZvu~?BlK<Su%X|7y(YMEc#ffm*PkC7 zdiVZ1zfsHSeTkMIKEJxb&~I9<^B0?XKQ;93CJwmc<d05j;_;98U((=pJX!@lZ zoO(kaJxvqTcYe6+SETdT8h>#6WvrpMS*-KlZsdGu=r`S~3GTS-JvhDnFM}@a4WGAH z8~U9Sw46_j{N5-m`NQYoa}9mn6rIua!w(GoIWz8Dd)~}^Ec-S0{-7Jr9R{q(UwfC9 zW2SAVtD)~V{&|Yg=So9w|D+~dVdzgAx`RFB*F}S~!_eD}&;-|>^754HGbXEoL97Er zpG!jX(d~v_@R-hBXbQamJ)NAbCjVWgzg{x=zjv9IA3isJ)X<-suQR&itHIEp56wsC zepkzRZ-vh9`r!`^{f;S`?%Mw?LtpYkO;_Kh;_@^Cg0wf!3<&uqyZo+!o~~Wbn*1xP zbv}9KUVhsQeG&aHzvneLhclkj$+;|oJ_Wky)BK1Q@LMBC;)2juJgo_%4E>nPHT`z8 z{+VIu(+s`4X|J3A14FMd4r{`_bMg1IoICE(0$lr-8G7EWnqFw+R~vf2yEMVI^V`tV zwRgA4fALJ6-}Q%?3|MK`rYcSEX5>F)=s9K~@A~swhTiai&WIbUUl#^~$k}7!u&cxO z4ZVvQ7v?sqv&7K%J*&&R?S0+Q3vbbMw_RO^Y5C!El|_c$+SJ=y7jvF4^xOMt!byg{ z!_Y6gUlWct^dp9A`Qder?9-%OlPM>^4jPKQ{F7#?jnz zA&O#SPGSguk;M3LjuT?bz>#yD1mgoS`Q5trR@JNb(eL$){Laq4?%P%M>f?UjTlHjI zI+ni__zOP4?Ns?ziGXM1Ckf*^= zoo6}|n&d+FMcfX(JA|&Tl;3`gzw3BEEAam#<9Y-CT#2CXQu|;11qLX6Jtgp8hrFe0 zpZOo}*8#rjSOjElHNdHz_q~ImU~A_3yujPS-*miR%V_87f6nbZ_8P9Qa);z7wg1#R zZH?x$bRaP|L_-H`iF;Uwj{bzh2;fAn?0?fdO*@ z{~LjSNa$D4uCf{Nb3?z)y9NFQ*j04tJp7r!Km9R=OLr@;xP#ldTI7Y!=RE>{Ksv5? z`*nezk@kO%o5MymZs)CnKiW=1;MYn!I&b$1`~~1!bSZ!P*8&gm?LQ0rI_L#-DPH}p zz#o@+djbDkIl0dLIs7XOSQPk0fxiTJN0&bLcLaXP2NheqY_lKqY6L0442c?~F2t4#JUD4t8 zpD*Lpc|IWUC!t5srQ^C=;2(Z_9R68>KLC88OXD@izz1m_{_ig_T-$l8z~39_U4JF; z(0~488{E$6$GDv<`Br(gz|RUo={$c<;F}M{pL;2uNBs%)v1tUT)y`q@8QGxSdZ!p40VJzE!pb9{SIJPv8&zOD=dy%6~`Tq22MK9=HFe_i(|N zNcmR^JoH!GBk*s$n+yIYDSrj%kj8uF0t0?o;0Fc%k$)P8pBH#2*M3vrcl;KYSA6~} zfiFRCqHCFNl@|~Axlg@~0owmHf&cYIhASU?v%rr@e|}2Z`Ha9X4c7h71%8X*&zzKB z-sb22wmetce~Z9>=>aZynUw!;fGf@j$lSgo<-dELq1w(>&`W4OL%-863p~_gzXW(% z`+p(jqjz!pc$~TJ9&-C@kn?nXo^O@^BJeHY=SnX>0s^Q0+$3`9#ZvwTfq!R}0WTDI zL*QYa%=-oY(NAzeEUUTxpTI-E&>9qDdTvPXI|9ETeB*i2&hG-AHV>EXa64y$^}R{p z&-n;9pmkpbIMH>e$9AOrw*}Al%X1$T_)*XYUAm566Zj|J$#9*|#dF-BFrV<8z;9pS z^5$J9_;@YwgXZCp2E(=ey9E9xuVlEc%cBAh{Z#)^;Gx`nF2+OcUm@~HrU~x~NuSS$ zrTp1njQ8h@0>9(!48NXlmG27ty8>4{d>iPKp8FBd8C`GSTji$LGCb6~-X!qQZv7L1 zpZPd9pmco|_&eDJE1zUI#Id({58~{&<^?^0>2FNN7re-Rjzv-m;cy%7;v?~UoG%3-{w;S z|FS4hho$@rU(fCQcaay0S6zW$A@r{By9E9-xYMQZKNR>^&|kWKmT#4PSWp_*mA}q_ zs|9{q;Q#A)7_cbtCj@?r;MGqH{JR2w4D(Hw(&_9y-2Mk;y|n!c0uS>LJ}B_ekM{+E z-!F6|2{m^Gsyz80__|E}O;|=qN@6RazsFc4(=;9`M#y15X`j_f&2Ub zg4*9#XMnEProfM`GW>;7{$YVX@vj)5bNgQfen1G$yax(J?t>yh?f*E&N0+d_%C`hQ z_il!3`4)#OxN*+ zZ{>DEJN-exbxr;Ld_>BJ{`?(wqTKg?2Kl2)Xs_J#06ZmBj!`~pC zI{N^(f4k7voWTEsz+WW%>iGiyTfj+9JuY(USpt8~uW&nI9@GrrRQ_8(!v*QxuXNoj z<$oOOPnXj5X9fP6!wi4fC4B$i0{)5Xc{?Yt|`raXdhkDnW1Rmn&69WGO@H4uU zF6P1SsQnXFJw|}*Sfr@AJtXD-?skUG z$d8{A__EBu*8OXN507y{rQbisx>Enc`1rR0-zRPQx9>^$=RU$vS+>ga!AGc_4~v{t z{2vSa27&*WH1;}yKM>&0M+N@;hq<7x`(FtBN#VEGOFOTCKDtjn`?uQwr~W)8@> z18x!cy#oJ7@<7e+x&i&B{)h8?NZ^kHAL-I{zenJqU*dNKe*1YY|5CnHo`LzL_W%6l z4EQO5&kOwKPcUFb;J+wvvUllHJby~y2M#e@+rQ%7-2VOljNzZ-Tcs)RugW|te!f%S z|MuftP}lv>1pe_r&b}PqssCYo@T|a3yqVj%PM-Td!1Y-IGB?5}YUleOW9TXQ@jB2g z!B5=J0PWAe06eXoN^3YCjd#wRnQ2wpondFAI~sR}(YP12wg&yqs1il(LA0?oSZ{7c z?eSnZikdqYDy>0pd#f|s>?@ z?^}eD<5QQw2eEZC3wK1L_b;k9^cwxKQ9oD%xUH|4 zz%&doB{IZQM~^mYYth=lLnmrz_4boDM$txp#|&U8iZD+b{Z2dTb$aVNXYAOIx4O03 z{^-`I*=`SO=Ze?EkZ9sCtR>Xm9!q6!P7hb>-4p9ojQiADw0aziar?>Rjq%)kw7QOo z>j)x5U7##2zUvds8Mj@XN8<)xqE>S><_==^_uDoSwNbHlc&@gBQp>hff6(qkSVKZ6 ztn1RbPRl$o!djY@(?vg0)o0kswqJxN)u=JPF{-yg65a7d#+MY_LBDm7UC>&+u^5@D zaLqI7Wemj(zt)(GYM4aa@XyZVskK?Nyp6HzArO+=qvb@Kvr(h7g&|f)z;d*r=xy+n z0JTI1m-q>X?fB4pEb4RHwLa?U3E@nLRT6Kcntcw7By~+ z8q227C?<5~NUzq~s;v@*paQSXWDGHDT%~I1r~oSFrt%QQpnfi4H%^mt~9a6pHxRogKlqMQNj*MZUi zqIPrK#0-aQWxn4z4~8U6f8scn?HGD1$4y&_3B*HaAsn_2qbJi)z)ycK3{6dSsBC zBpv>Z=az;T$eT~47%z@@pxxAu zt)fqmxrd_qG031=?cB;*bY$DH&!RZ(kV2`pkq{f;GmWUV*=gO$5__xDul3N&Ibms- zNM2~2Pau6J1roy+hES8`!CEkb&q57wyu)+#Rr=Y99_9%wOjf~R6EY;p)D}kF*D^-X z@)xCgTaKt6w1|<J(}aWbhMXhl zGd(C>_0!-$j>eB{L&Lxtu&`YfHN#hpb~7h)Rp1{w7o8;a(F!b;%9#Z084-)nZATEk zq~J`8Wh~8=4Pkv)hib9r)KVssrw|xK72U2e-Wn5rtrHjJ*@oGGX@r8n7!}aHXmk$h zsGLQsXK57X>!wGcWbcr|kUveWT3Cq``pL|(TADfT6&8_b*y@}a=bI!`s(8L&oG&aG zN!RoQqfrgx!qMqJI=NUdQql`qKSVb)>Sd7G*mT?c7>aBL{h`Sb`g4-pf>b+ zb}dU9y+)$ce16Rmdlp>%^#?b)AYX2}D=hqTiK zO=+V_M&r%l;5^(TZEh=R%%WI)RH~Mci_r6Pth5Zbbre<2_I?t|#GRj63s+X1c7C*7 zAp$%FJjY@_Zg%@)^1R)((}}hRBWS`oVij!P>Ya*&XU`ft@hp_agf*yTNZ*9t5e77r zLb9C;2pK5iATx-%`Z3YTLoz7O*5?-DgZIWw)+{~1W1Kn5Y!v8lompi(4qF~r(2@aT z%E}FR$saI$?M=2<;jJFGHV+(to95u5dQ_d6Po*tEVMq?giouNXOe@bigz6%!!Qoi> zS&o~hyJ-o+myy-yTCPDwFHARCxEvJ0V2fC%p1xuvdt<-2tF7dp%y1SE(ITNS~%orLgZsOAv%derzsCSIEIBt|~(C zz&D?ClUffrCO1N42^y|ZP{>Gex1M$OKiICgPMU=e&7A?MzQA!e|_Bv=dZ=4q=7DHiX_0e~JeC}2fcQGx1;b9WR~LWOQkS_S^w6znyDm^yArAbDGTVoh8$Q6B8%UsLB{STMpEy$I~O8}OPn5w)3Q-RG5TgK z6dIi;lolvtj|iCtUVyJ~_|;6HVPt~45po=ePMnel)xnQVdvu{OR(c3ZIdt^ru%LIx zF-fnxQ?U%^ByoW~oytIZ&ee|rd25VU&Qk%gYcdyLCJ!j7A=B{oDIR9vDinylM5h>y zhQ1ZXCeRg_UNU|WH7VM*($av$0>#o+vE1NGaqp&~ooWXH_vWEeP zAe}ucqzmTFRA{Oj4gTGkO1ClqIJGl%q!eV>5#Bj+J@EcmrFq#!H<>ZFz*haPGUh_gUO*om+-k52i49tYaa>=UhYz&6*OGAi-&m%HQ%~#l;s83`? ziFh%In;1~;g4On`CmR|Sp{?)lUIB6<5I4=Y!MxEQsk_&dV%`&@A75F585dBUW_P`Xt$Itd|-0UR`Hknt&yD=JIr z%n$*MqY4^D+NO!X_Z(^*ZFS}N zrznGqHyH#w8vH@#< zd6vQI**wz##OIj?8OmlHAyg2dQ@f$kWuz2AQSDiGm3xYD{HO!mpdVQDk=tgFMLUDc z^$Qmwu+`Ck{G{WH(YaYBv)yz?ytUr6c?g_0e_#T3{;<$#NoXkw$qF$W_U|DDgw+j9 zC+`n%tch4(Z0~`U@wHlF`pQ)HIAqC4DhXe8>v`!ms~7~u)@TZB`arkeLi#f@vod67 zjK|R$VhYOgN=ZtLHO1@_T?ssiY1w{jk?&ba$q|IZ1`EZ~*hhE|KZ-Iq^hZ2Pl=hHM z{h&)TonDrCt0*4s+Km&_tSG&J)R8pf3vesnrT{2^G{1!Bf@7$XScbPiB*8-~WUtTWx|9o}<{`g4jE^%y%# z6+&)`c`FVXN-295V8&Q37qer^&tu*a5eMw{>pkEDYz?!w#SlT~E+9y{6!iw6#!1r4 z%titUl1XB;MC?MPgE8lxvyxnRN-(`T0}S}ck2=_Lx) zNet63wx1@<4FSGME}jNEQYnVR93;P?=`)Uo5e*`u%utgceJIdH#vn!mgX*= zGMYRq+@Pm=n9!e?p(zQ~WUWx>*|1)eNeQlH_zg4kL>Kc8%n@&SLJx3~Hm5NhVIz}w zfCP!Lx(pupVZ@S4LOdDMOH_?0pzH&{f|-48GAU;Nn)9W~!crCu5{fgjXdD%k=bX8L z1jUJrl`%X8+8CTfjM3v3v+hFO02#Zavhi=V(0I3SVf9(qu%u7oA%+Ub?O zwW=RXSUId9*ED40G`lcrC8%zKMM)!E7Sd)>RUSPQ!4|G z`#CDti7%nUB7TE-36rYHs4&sZO#R#X2*BZXW6L>J#`vsB2wA_iDw;m8CfSh|c#SC& z(+uDD>KbXN;n+Z?m>g4VD%?Oux7~?sb|;$T@kNrMv$99mg$c}dLz8C(R(PR17Q@kI zSz!kZ_UvOWQ#bKv=Oe(wa~wm@FkhjXk{t;msHIq{yPh)QNHK+xwOjI(VI*nJC-lTb zjM-#|o!oO7HxmqENWX;VkcFh#$W2oh54;EKRs&jTrk&zP9$(7bol{Vvfb@W=!Vc(z0wLz7G*gsl-Aii)G5>7lx)ad0Ro2x#6c%Ia0-5@;$XW!c8Q^wlm_c_{FlG zsad9=1gZ>_|G4;X2TL6uirJ)GtYT|H33X6U9ba9L6`l2iDgi3w)0l|wk~fXp2| zhl3LrfqFdFz!9C`c51A-ax|>H690s*`5R_HdX{f*OUc9R|t$MIw*kI^@6Hmvg5Kq;}QGe(jV8OKlKNy{m0 zA@GWJA=zTmIhbVGFHRRsC?J7PRXnfQ}7wpYUi#UoPJ{_qU|Focw1!N|Wnu>kPirpa+RYuX#xs_gm_cH5M@9l$s}|!&=2%3> z9LU1RN_%ixHb^F(OYSRzMsx6XKdS|!*6)iCY-`6bNFIcn+9BvuRWYxrz1cZdt@^qq^9DMW6X##GHt&qi zG`m~Q=|-oN(YWD4hX)IrzD76;4<~dMKhb~=7n?$qARb2hx*#uc`bEm_t|wmAwDNQ#gY`%s57aQ zdHF6uMndL^lquUQeI-97;V0d{={97F{t>O+dRUKX^*7?s@>&C?_z3c1xt>wwZ81;< zFGU~DIPs8_5Y>lwog?JAjDRhWZhWMQ&x9dxiR+X)rAwXtmVTyHXJQc)Lvxc41;qS# zhvB3t65y@Y>$zt_nF2mO&rEwTwEax&OO(S<<%b56lafbDr=4WSq@EV%L%0?+&t^EG zT*D7;dWj?y$;FCM^e^w*NqBY$Gt-hHeCj0=A9fZi*ky&Y(KvC2h}{c91{=gO{7h@o zq@Dk1k-Uhr^I)p8)8z}Kg@=+#3T7e$|BP6(X^JlX5$6PXoG>^M*UgHz79=%F9Sh+k z;@-5Ed*Vn21!g%WyrXCHw9OFtF(fcDbvTv9N75)@y4oXsNI~QjkTgO=*JaCoF@*xU zqdCPpZ#-FQEK^GCMB){YiR7oGj}v-xtO6ZKBggwF*4X$UG9tu5{d8p@q;Qfr`ctkL zalHw_$AYdr#qDV(+n|AOG9d28c}`)}EnBO03J&HvnZuT5N9dy9@uf*Qv?!F?uXYaZHh^EsYeN$?LRZZ#qpPhHg1hVYN3r&(Cxsbs@P!o%g59RtB33mxq@r zOpS(KaIu(GfQpP}nUblzKfYStsntnkf>eOiU7^WStYO=kT^e3DV+5YlBZz&AKdf}P z?b&8;Hu)-G5-zQG+ub3XzuqCmbU=0uZ@J(t-No(V9HW?0V}xuWdMTPoc?7t4N6OI% zTdoOn^OiB6mkWc!V_Jh9&9U*0CHFQCd6*0iSty{j*xKqe?QwD$-aG5li^pa&rHL;X zXJs$T0v$6$4lmE3qa{q@9Ri5F$SFA<*=Njon`y!$$o7VScXi|v5O>uEPvR*;MLigP z6f}KA1(&>7j=5bXB>beFR*}C;JqxFe$aFq`W>?Fsdt-Yq%-^gGPzVG~7D$bF0Bz`C z>XZ0e)}83#zMl-WJ5QkwSWdulS&h`NTG<#L83M;!&_n0rM@HzTs~daGJ8=LZy*vj= z(2#*jJw!No7-DaDZ4kZGfZmw1jgv%hOc%c^;3TlEPMfV1U{1j}#he$_d3iJDgVZZ5 zyL0iQi&fg+T}TFN<7TNX_p(;aYVPqWc(QVM^I8k?cGBB-!yh)LS3NSX}`2eVz#JAwwwl1|uV?KO}1 zI2qhy^EQ+oD*cIgAm|rHK`gLSG%tXx`s}=b1aX5Sr@ov-gW8#r4Lpw|8`-p)DnR?* znc1fDG@VjqvEo?E+2xQu&1?pQBDuPx>E6weo~Raks^c8S%ZPc>qZRW)W9DJH`s6lE z$uvngD!rGb6vAhkm2LYHvm(>(#Tlm(4}tpxM_^+`#OLDZxI9n5;s+=EW6D4ZN?ZO( zJvna@N|1kgmGOqfl@LO|^c8B=ycJQTpp_-(5T9n8?;M(Tv(avu05cP_V`11a z=d7h19b6ItJi8;#Ws1H(iDKn3E+gATTn3WkG|Bi>*3J#XO~`=)rj)sNBjrdm_bdq$ zsLl;t)hMdMl|pxs=y~~DvY6G_q6I>?rUpMcJ>-tLGg=sAxN`+WO+Km3S5C@AC*`P8 z`_7^)y{xEy5!;4?dDK%8(>zo>*y+ z9x`TWjM4gN_rtM$HBl+(LFEs8-UDoI;SGzne45Ffk-rh z8+m=Ob&1}?$nUyBOL-9?N~0nZ5XJ0RT=bC98s;12bGTQ*757?AmCfOiOvWoR_$1#5 z2Yyk)$Iay6!pW-47VI#l2*M>c|4h!*2%XvLv9)%L+rQ~HD@`RtXsKweB#z_8IR)w& zp`LsC1vEjK&+cGk@?93{Ku~&qBBo3tIyK>uLIWTOD8HQc$di*jdK`M|zsJ%BfXW)o zyB3JFp>2{tOkaS~c5-5SC|SW1-}Dn6N<{=5M&B_67k%Fyt8!>J*=du#Wjr%y)5D0O zG7>$)L>d0Q)m?8zt;*3R2~BIaFSe{`jnKO_ts0#sSkWdP5=_J!2S?v z&XZ7(^XSYCCH0_69F0KZ(U~2)&dvGam+v&Qs>y%c)iHIX zyq)I|3wxGUjF5@7s53+gPFW`B+RmJjvP~KZMoHLaXCQaiqxQ`KfeYAGic zrr7Y|JMr)m0pO=*k3n85kJnr{lWQO|zB_5{;aGetj8z`>*-7~Vx{B{9H8K&?vGDh5 z1DLbT3uknfWga%eITk?7rY%pOjB^gCy@v;VM80-fV-Sf>t1KzKw2>SuVJ6NVX^xY3 z7DEFheJF?R5Z4I#O+LLlot`3JWf(7{saOL6pMvRWEX=>h9RnU`-<6H&OT~hES8QKF zsI#*yC&z;3B_*&*Ply0bTBiZOTF3b`QoL${lPkVk$fY`T-$e!hPmFIkLMJENT*DdL9@NAojsba&Vho3LGK0%I@S zG|mL`cAKRCF@eo0>r!}$o>4<50Ia8ZG9BYpfi{iBo7n5TH_e(fk#PG>dGw!*{k!tG z#+gd&*45_a-BuizlT?8noS8e z>6NieBaX;Iu$sOu6;>cEs$|6>&U{T1hgku$vi6&C{^W))#PZ2{U{T#Ib$@+2DHm-r zLxw@|&k#%a#nYq8AW|5cQb%-w4Ge}&GUb`6itg}h!A>#y<)?SPTS z^7JsSsAqqH6q5WXS6O`7wL%=%9x|{WIG3vs$MuUq0TYqM!aUmO;f;?x@ehT7<#c-#D##}|BRM6>h4e3E9&-K`y4WMLXuqZQ@(FRAaBpmotsk$-gvw{E&lAuUG z&C*Ui6iqxY>~GL^N`jSgNKzV#vIO!e#n1Z`BawV98OR2%peKH2>emIIpZ|&|_DCfC zCGeJ+Ge#)`!F)=RY3@II$dhCOs?%w@l{Cd*Uo7pg~bPKa@eJ6if6WjvMP-r7|idZV)bbq&7!1N>?I zWvQ?CeSTqles=JE3E%ztr=`B$uMNuoQ1HDT)W2Km>wRBPKCFKme*ex7elXDfKO*(@ zeuLD%RPJH_n}GjA{Av9!N`1ZWlLyimY3{WCmH13o7k^Ym>pw{aaq0bg&*Ja;e>nel z;fEi1{r|>~a7n$NmWtYceU9E=kKg~!tAF4!uAuh^r9O3w`lpOyKf`d8sEtp5SP=n>j}WgouKwa@%tA^i5QaQ)wd zAN~6K_Hk*w&+5RW5$Rq<@4pq)U-@Y+sCO+V)one6e05$N3k%zbEKGxPD&?>Q}zZ_4R&WS-#6HeE$Co>L0k2dQ++B{Y7?Q2AmlG-vCS~ zFKAl1@Dp7B!gKi^&bK~a@6SZB=Xv$-llu2beJ#gNclfXH=b=8~zCQm!ssErpU-~a> z#nO-V>rvFDo@)I^uI7F}av9(6;F~_)*4O7>iQlP+*01c73YYU;>0BGoditFnM=-5_ zKuI*8kZ6uFd)PV2MqQTjcrMFXslX#%&RQ+J7C_a{$x6 lb4mXHGspP}ZzKleUHV)F{U|=9)qmNOT=FGBh2U%D{{tX;V5|TD literal 0 HcmV?d00001 diff --git a/solution.cpp b/solution.cpp new file mode 100644 index 0000000..1cfc616 --- /dev/null +++ b/solution.cpp @@ -0,0 +1,141 @@ + +// include sets +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +typedef pair pairs; +typedef unsigned int uint; + +/** + * @brief depth first search to find the word + * @param board: A list of pair coordinates to check for the next move in s + * @param s: The string to check for + * @param board: A map of the board to check for the next move in s + * @param path: The path taken so far, do not repeat + * @param boardKeys: The keys of the board, used to find adjacent points + * @return: A boolean indicating if the string can be found on the board + */ +bool dfs(set &points, string s, map &board, set &path, set &boardKeys) +{ + // cout << s << ' '; + // for (auto it = points.begin(); it != points.end(); it++) + // { + // cout << '(' << it->first << ',' << it->second << ") "; + // } + // cout << endl; + if (s.length() == 0) + return true; + for (auto it = points.begin(); it != points.end(); it++) + { + // cout << "checking " << it->first << ',' << it->second << " '" << board[*it] << endl; + if (board[*it] == s[0]) + { + path.insert(*it); + // find all points that are adjacent to it LRUD + set adj; + adj.insert(pairs(it->first - 1, it->second)); + adj.insert(pairs(it->first + 1, it->second)); + adj.insert(pairs(it->first, it->second - 1)); + adj.insert(pairs(it->first, it->second + 1)); + // find the intersection of adj and all possible points on the board + set intersection; + // get the keyset of board + set_intersection(adj.begin(), adj.end(), boardKeys.begin(), boardKeys.end(), inserter(intersection, intersection.begin())); + // remove the points that are already in the path + set new_points; + set_difference(intersection.begin(), intersection.end(), path.begin(), path.end(), inserter(new_points, new_points.begin())); + if (dfs(new_points, s.substr(1), board, path, boardKeys)) + return true; + path.erase(*it); + } + } + return false; +} + +bool exist(vector> &board, string word) +{ + set points; + set boardKeys; + map board_map; + map board_char_count; + for (uint i = 0; i < board.size(); i++) + { + for (uint j = 0; j < board[i].size(); j++) + { + points.insert(make_pair(i, j)); + board_map[make_pair(i, j)] = board[i][j]; + boardKeys.insert(make_pair(i, j)); + if (board_char_count.find(board[i][j]) == board_char_count.end()) + board_char_count[board[i][j]] = 1; + else + board_char_count[board[i][j]]++; + } + } + set path; + + map word_char_count; + for (uint i = 0; i < word.length(); i++) + { + if (word_char_count.find(word[i]) == word_char_count.end()) + word_char_count[word[i]] = 1; + else + word_char_count[word[i]]++; + } + + // check the case where any character in the word does not appear on the board + for (uint i = 0; i < word.size(); i++) + { + if (board_char_count.find(word[i]) == board_char_count.end()) + return false; + else if (board_char_count[word[i]] < word_char_count[word[i]]) + return false; + } + + return dfs(points, word, board_map, path, boardKeys); +} + +int main(void) +{ + // assume input comes from stdin + // board input is single characters, space separated for columns and newlines for rows + // word is on its own line + // example input: + // ``` + // A B C E + // S F C S + // A D E E + // word + // ``` + + // read board and word + vector> board = {{'A', 'A', 'A', 'A', 'A', 'A'}, + {'A', 'A', 'A', 'A', 'A', 'A'}, + {'A', 'A', 'A', 'A', 'A', 'A'}, + {'A', 'A', 'A', 'A', 'A', 'A'}, + {'A', 'A', 'A', 'A', 'A', 'A'}, + {'A', 'A', 'A', 'A', 'A', 'A'}}; + + string word = "AAAAAAAAAAAAAAB"; + + // print the board and word + cout << "Board:" << endl; + for (uint i = 0; i < board.size(); i++) + { + for (uint j = 0; j < board[i].size(); j++) + { + cout << board[i][j]; + } + cout << endl; + } + cout << "Word: " << word << endl; + + // print result + cout << exist(board, word) << endl; +} \ No newline at end of file diff --git a/solution.py b/solution.py index 4435b2c..f092ede 100644 --- a/solution.py +++ b/solution.py @@ -51,16 +51,16 @@ def exist(board: list[list[str]], word: str) -> bool: # word # ``` - board = [] - word = None - while (True): - line = input().split(" ") - if (len(line) == 1): - word = line[0] - break - board.append(line) + board = [["A","A","A","A","A","A"],["A","A","A","A","A","A"],["A","A","A","A","A","A"],["A","A","A","A","A","A"],["A","A","A","A","A","B"],["A","A","A","A","A","A"]] + word = "AAAAAAAAAAAAAAB" + # while (True): + # line = input().split(" ") + # if (len(line) == 1): + # word = line[0] + # break + # board.append(line) - print(board) - print(word) + # print(board) + # print(word) print(exist(board, word)) diff --git a/submissionCode.cpp b/submissionCode.cpp new file mode 100644 index 0000000..ad5e455 --- /dev/null +++ b/submissionCode.cpp @@ -0,0 +1,106 @@ + +// include sets +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +typedef pair pairs; +typedef unsigned int uint; + +/** + * @brief depth first search to find the word + * @param board: A list of pair coordinates to check for the next move in s + * @param s: The string to check for + * @param board: A map of the board to check for the next move in s + * @param path: The path taken so far, do not repeat + * @param boardKeys: The keys of the board, used to find adjacent points + * @return: A boolean indicating if the string can be found on the board + */ +bool dfs(set &points, string s, map &board, set &path, set &boardKeys) +{ + // cout << s << ' '; + // for (auto it = points.begin(); it != points.end(); it++) + // { + // cout << '(' << it->first << ',' << it->second << ") "; + // } + // cout << endl; + if (s.length() == 0) + return true; + for (auto it = points.begin(); it != points.end(); it++) + { + // cout << "checking " << it->first << ',' << it->second << " '" << board[*it] << endl; + if (board[*it] == s[0]) + { + path.insert(*it); + // find all points that are adjacent to it LRUD + set adj; + adj.insert(pairs(it->first - 1, it->second)); + adj.insert(pairs(it->first + 1, it->second)); + adj.insert(pairs(it->first, it->second - 1)); + adj.insert(pairs(it->first, it->second + 1)); + // find the intersection of adj and all possible points on the board + set intersection; + // get the keyset of board + set_intersection(adj.begin(), adj.end(), boardKeys.begin(), boardKeys.end(), inserter(intersection, intersection.begin())); + // remove the points that are already in the path + set new_points; + set_difference(intersection.begin(), intersection.end(), path.begin(), path.end(), inserter(new_points, new_points.begin())); + if (dfs(new_points, s.substr(1), board, path, boardKeys)) + return true; + path.erase(*it); + } + } + return false; +} + +class Solution +{ +public: + bool exist(vector> &board, string word) + { + set points; + set boardKeys; + map board_map; + map board_char_count; + for (uint i = 0; i < board.size(); i++) + { + for (uint j = 0; j < board[i].size(); j++) + { + points.insert(make_pair(i, j)); + board_map[make_pair(i, j)] = board[i][j]; + boardKeys.insert(make_pair(i, j)); + if (board_char_count.find(board[i][j]) == board_char_count.end()) + board_char_count[board[i][j]] = 1; + else + board_char_count[board[i][j]]++; + } + } + set path; + + map word_char_count; + for (uint i = 0; i < word.length(); i++) + { + if (word_char_count.find(word[i]) == word_char_count.end()) + word_char_count[word[i]] = 1; + else + word_char_count[word[i]]++; + } + + // check the case where any character in the word does not appear on the board + for (uint i = 0; i < word.size(); i++) + { + if (board_char_count.find(word[i]) == board_char_count.end()) + return false; + else if (board_char_count[word[i]] < word_char_count[word[i]]) + return false; + } + + return dfs(points, word, board_map, path, boardKeys); + } +}; \ No newline at end of file From 4d917086c67963955d3d6b330b16fae00f0c5bc7 Mon Sep 17 00:00:00 2001 From: Cole Fuerth Date: Fri, 2 Dec 2022 15:18:44 -0500 Subject: [PATCH 07/12] remade solution, optimized in C++ --- Makefile | 2 +- solution.cpp | 47 +++++++++++++++++++++++++++-------------------- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/Makefile b/Makefile index 7851363..c32de57 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ build: g++ -o solution solution.cpp -Wall -Wextra run: build - /usr/bin/time -v ./solution < sample_input.txt + /usr/bin/time -v ./solution clean: rm -f solution \ No newline at end of file diff --git a/solution.cpp b/solution.cpp index 1cfc616..7197caf 100644 --- a/solution.cpp +++ b/solution.cpp @@ -27,33 +27,32 @@ bool dfs(set &points, string s, map &board, set &path // cout << s << ' '; // for (auto it = points.begin(); it != points.end(); it++) // { - // cout << '(' << it->first << ',' << it->second << ") "; + // cout << '(' << it.first << ',' << it.second << ") "; // } // cout << endl; if (s.length() == 0) return true; - for (auto it = points.begin(); it != points.end(); it++) + for (auto it : points) { - // cout << "checking " << it->first << ',' << it->second << " '" << board[*it] << endl; - if (board[*it] == s[0]) + // cout << "checking " << it.first << ',' << it.second << " '" << board[it] << endl; + if (board[it] == s[0]) { - path.insert(*it); + path.insert(it); // find all points that are adjacent to it LRUD set adj; - adj.insert(pairs(it->first - 1, it->second)); - adj.insert(pairs(it->first + 1, it->second)); - adj.insert(pairs(it->first, it->second - 1)); - adj.insert(pairs(it->first, it->second + 1)); - // find the intersection of adj and all possible points on the board + adj.insert(pairs(it.first - 1, it.second)); + adj.insert(pairs(it.first + 1, it.second)); + adj.insert(pairs(it.first, it.second - 1)); + adj.insert(pairs(it.first, it.second + 1)); + // remove adjacent points that are not on the board set intersection; - // get the keyset of board set_intersection(adj.begin(), adj.end(), boardKeys.begin(), boardKeys.end(), inserter(intersection, intersection.begin())); // remove the points that are already in the path set new_points; set_difference(intersection.begin(), intersection.end(), path.begin(), path.end(), inserter(new_points, new_points.begin())); if (dfs(new_points, s.substr(1), board, path, boardKeys)) return true; - path.erase(*it); + path.erase(it); } } return false; @@ -61,10 +60,14 @@ bool dfs(set &points, string s, map &board, set &path bool exist(vector> &board, string word) { - set points; - set boardKeys; - map board_map; - map board_char_count; + // reverse the word + string rword = word; + reverse(rword.begin(), rword.end()); + + set points; // points to check for the next move + set boardKeys; // keys of the board, for checking for valid adjacent points + map board_map; // coordinate -> char map of the board + map board_char_count; // char -> count map of the board for (uint i = 0; i < board.size(); i++) { for (uint j = 0; j < board[i].size(); j++) @@ -98,6 +101,10 @@ bool exist(vector> &board, string word) return false; } + // use word if the first character has less occurences than the reverse of the word + if (board_char_count[word[0]] > board_char_count[rword[0]]) + word = rword; + return dfs(points, word, board_map, path, boardKeys); } @@ -119,10 +126,10 @@ int main(void) {'A', 'A', 'A', 'A', 'A', 'A'}, {'A', 'A', 'A', 'A', 'A', 'A'}, {'A', 'A', 'A', 'A', 'A', 'A'}, - {'A', 'A', 'A', 'A', 'A', 'A'}, - {'A', 'A', 'A', 'A', 'A', 'A'}}; + {'A', 'A', 'A', 'A', 'A', 'B'}, + {'A', 'A', 'A', 'A', 'B', 'A'}}; - string word = "AAAAAAAAAAAAAAB"; + string word = "AAAAAAAAAAAAABB"; // print the board and word cout << "Board:" << endl; @@ -138,4 +145,4 @@ int main(void) // print result cout << exist(board, word) << endl; -} \ No newline at end of file +} From ad8d5692dbcea2c38e7b9a74ded911cc68d18430 Mon Sep 17 00:00:00 2001 From: Cole Fuerth Date: Fri, 2 Dec 2022 15:18:54 -0500 Subject: [PATCH 08/12] apply optimizations to python, too --- solution.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/solution.py b/solution.py index f092ede..22fe153 100644 --- a/solution.py +++ b/solution.py @@ -30,6 +30,15 @@ def exist(board: list[list[str]], word: str) -> bool: board = {(x, y): board[x][y] for x, y in product( range(len(board)), range(len(board[0])))} + # if any char in the word is not in the board, return False + if not set(word).issubset(set(board.values())): + return False + + # if there are less occurences of the last character than the first character, reverse the word + boardstr = ''.join(board.values()) + if boardstr.count(word[0]) > boardstr.count(word[-1]): + word = word[::-1] + # you take the input, and see if for each character, you can follow a path from character to character. The same character cannot be used more than once return search( set(board.keys()), @@ -51,16 +60,8 @@ def exist(board: list[list[str]], word: str) -> bool: # word # ``` - board = [["A","A","A","A","A","A"],["A","A","A","A","A","A"],["A","A","A","A","A","A"],["A","A","A","A","A","A"],["A","A","A","A","A","B"],["A","A","A","A","A","A"]] - word = "AAAAAAAAAAAAAAB" - # while (True): - # line = input().split(" ") - # if (len(line) == 1): - # word = line[0] - # break - # board.append(line) - - # print(board) - # print(word) + board = [["A", "A", "A", "A", "A", "A"], ["A", "A", "A", "A", "A", "A"], ["A", "A", "A", "A", "A", "A"], [ + "A", "A", "A", "A", "A", "A"], ["A", "A", "A", "A", "A", "B"], ["A", "A", "A", "A", "B", "A"]] + word = "AAAAAAAAAAAAABB" print(exist(board, word)) From 65a94f0b43ca03e74e2233e67ce87d3e6d2e94a9 Mon Sep 17 00:00:00 2001 From: Cole Fuerth Date: Fri, 2 Dec 2022 15:22:21 -0500 Subject: [PATCH 09/12] add gitignore and remove temp files --- .gitignore | 3 ++ .vscode/settings.json | 21 --------- solution | Bin 127336 -> 0 bytes submissionCode.cpp | 106 ------------------------------------------ 4 files changed, 3 insertions(+), 127 deletions(-) create mode 100644 .gitignore delete mode 100644 .vscode/settings.json delete mode 100755 solution delete mode 100644 submissionCode.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f51e39a --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.vscode/ +solution +submissionCode* diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index f589c77..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "files.associations": { - "*.c": "c", - "*.lex": "lex", - "*.pl": "prolog", - "*.rkt": "racket", - "deque": "cpp", - "string": "cpp", - "vector": "cpp", - "unordered_set": "cpp", - "unordered_map": "cpp", - "map": "cpp", - "ostream": "cpp", - "array": "cpp", - "string_view": "cpp", - "initializer_list": "cpp", - "set": "cpp", - "*.tcc": "cpp", - "utility": "cpp" - } -} \ No newline at end of file diff --git a/solution b/solution deleted file mode 100755 index ee6503c805f739bafeebf1e5e8f03eb955ede1dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 127336 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 diff --git a/submissionCode.cpp b/submissionCode.cpp deleted file mode 100644 index ad5e455..0000000 --- a/submissionCode.cpp +++ /dev/null @@ -1,106 +0,0 @@ - -// include sets -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; -typedef pair pairs; -typedef unsigned int uint; - -/** - * @brief depth first search to find the word - * @param board: A list of pair coordinates to check for the next move in s - * @param s: The string to check for - * @param board: A map of the board to check for the next move in s - * @param path: The path taken so far, do not repeat - * @param boardKeys: The keys of the board, used to find adjacent points - * @return: A boolean indicating if the string can be found on the board - */ -bool dfs(set &points, string s, map &board, set &path, set &boardKeys) -{ - // cout << s << ' '; - // for (auto it = points.begin(); it != points.end(); it++) - // { - // cout << '(' << it->first << ',' << it->second << ") "; - // } - // cout << endl; - if (s.length() == 0) - return true; - for (auto it = points.begin(); it != points.end(); it++) - { - // cout << "checking " << it->first << ',' << it->second << " '" << board[*it] << endl; - if (board[*it] == s[0]) - { - path.insert(*it); - // find all points that are adjacent to it LRUD - set adj; - adj.insert(pairs(it->first - 1, it->second)); - adj.insert(pairs(it->first + 1, it->second)); - adj.insert(pairs(it->first, it->second - 1)); - adj.insert(pairs(it->first, it->second + 1)); - // find the intersection of adj and all possible points on the board - set intersection; - // get the keyset of board - set_intersection(adj.begin(), adj.end(), boardKeys.begin(), boardKeys.end(), inserter(intersection, intersection.begin())); - // remove the points that are already in the path - set new_points; - set_difference(intersection.begin(), intersection.end(), path.begin(), path.end(), inserter(new_points, new_points.begin())); - if (dfs(new_points, s.substr(1), board, path, boardKeys)) - return true; - path.erase(*it); - } - } - return false; -} - -class Solution -{ -public: - bool exist(vector> &board, string word) - { - set points; - set boardKeys; - map board_map; - map board_char_count; - for (uint i = 0; i < board.size(); i++) - { - for (uint j = 0; j < board[i].size(); j++) - { - points.insert(make_pair(i, j)); - board_map[make_pair(i, j)] = board[i][j]; - boardKeys.insert(make_pair(i, j)); - if (board_char_count.find(board[i][j]) == board_char_count.end()) - board_char_count[board[i][j]] = 1; - else - board_char_count[board[i][j]]++; - } - } - set path; - - map word_char_count; - for (uint i = 0; i < word.length(); i++) - { - if (word_char_count.find(word[i]) == word_char_count.end()) - word_char_count[word[i]] = 1; - else - word_char_count[word[i]]++; - } - - // check the case where any character in the word does not appear on the board - for (uint i = 0; i < word.size(); i++) - { - if (board_char_count.find(word[i]) == board_char_count.end()) - return false; - else if (board_char_count[word[i]] < word_char_count[word[i]]) - return false; - } - - return dfs(points, word, board_map, path, boardKeys); - } -}; \ No newline at end of file From 279adee3ba78a724ae778542a674f7a9d0c6c709 Mon Sep 17 00:00:00 2001 From: Cole Fuerth Date: Fri, 2 Dec 2022 15:37:00 -0500 Subject: [PATCH 10/12] clean up solutions --- Makefile | 2 +- sample_input.txt | 4 ---- solution.cpp | 12 +----------- solution.py | 1 - 4 files changed, 2 insertions(+), 17 deletions(-) delete mode 100644 sample_input.txt diff --git a/Makefile b/Makefile index c32de57..4c534a2 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ build: g++ -o solution solution.cpp -Wall -Wextra run: build - /usr/bin/time -v ./solution + ./solution clean: rm -f solution \ No newline at end of file diff --git a/sample_input.txt b/sample_input.txt deleted file mode 100644 index 842191f..0000000 --- a/sample_input.txt +++ /dev/null @@ -1,4 +0,0 @@ -A B C E -S F C S -A D E E -SEE diff --git a/solution.cpp b/solution.cpp index 7197caf..51961ac 100644 --- a/solution.cpp +++ b/solution.cpp @@ -14,7 +14,7 @@ typedef pair pairs; typedef unsigned int uint; /** - * @brief depth first search to find the word + * @brief depth first search to find the word. For each potential point, we recursively scheck valid next points that are not visited yet. * @param board: A list of pair coordinates to check for the next move in s * @param s: The string to check for * @param board: A map of the board to check for the next move in s @@ -24,30 +24,20 @@ typedef unsigned int uint; */ bool dfs(set &points, string s, map &board, set &path, set &boardKeys) { - // cout << s << ' '; - // for (auto it = points.begin(); it != points.end(); it++) - // { - // cout << '(' << it.first << ',' << it.second << ") "; - // } - // cout << endl; if (s.length() == 0) return true; for (auto it : points) { - // cout << "checking " << it.first << ',' << it.second << " '" << board[it] << endl; if (board[it] == s[0]) { path.insert(it); - // find all points that are adjacent to it LRUD set adj; adj.insert(pairs(it.first - 1, it.second)); adj.insert(pairs(it.first + 1, it.second)); adj.insert(pairs(it.first, it.second - 1)); adj.insert(pairs(it.first, it.second + 1)); - // remove adjacent points that are not on the board set intersection; set_intersection(adj.begin(), adj.end(), boardKeys.begin(), boardKeys.end(), inserter(intersection, intersection.begin())); - // remove the points that are already in the path set new_points; set_difference(intersection.begin(), intersection.end(), path.begin(), path.end(), inserter(new_points, new_points.begin())); if (dfs(new_points, s.substr(1), board, path, boardKeys)) diff --git a/solution.py b/solution.py index 22fe153..ef82966 100644 --- a/solution.py +++ b/solution.py @@ -39,7 +39,6 @@ def exist(board: list[list[str]], word: str) -> bool: if boardstr.count(word[0]) > boardstr.count(word[-1]): word = word[::-1] - # you take the input, and see if for each character, you can follow a path from character to character. The same character cannot be used more than once return search( set(board.keys()), word, From 3c2440b8692ab5b75b6a3bcc63c9f13609c91259 Mon Sep 17 00:00:00 2001 From: Cole Fuerth Date: Fri, 2 Dec 2022 15:37:17 -0500 Subject: [PATCH 11/12] add exact leetcode submission code for jeremie-kun --- leetcode/solution.cpp | 103 ++++++++++++++++++++++++++++++++++++++++++ leetcode/solution.py | 45 ++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 leetcode/solution.cpp create mode 100644 leetcode/solution.py diff --git a/leetcode/solution.cpp b/leetcode/solution.cpp new file mode 100644 index 0000000..11971c8 --- /dev/null +++ b/leetcode/solution.cpp @@ -0,0 +1,103 @@ + +// include sets +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +typedef pair pairs; +typedef unsigned int uint; + +/** + * @brief depth first search to find the word. For each potential point, we recursively scheck valid next points that are not visited yet. + * @param board: A list of pair coordinates to check for the next move in s + * @param s: The string to check for + * @param board: A map of the board to check for the next move in s + * @param path: The path taken so far, do not repeat + * @param boardKeys: The keys of the board, used to find adjacent points + * @return: A boolean indicating if the string can be found on the board + */ +bool dfs(set &points, string s, map &board, set &path, set &boardKeys) +{ + if (s.length() == 0) + return true; + for (auto it : points) + { + if (board[it] == s[0]) + { + path.insert(it); + set adj; + adj.insert(pairs(it.first - 1, it.second)); + adj.insert(pairs(it.first + 1, it.second)); + adj.insert(pairs(it.first, it.second - 1)); + adj.insert(pairs(it.first, it.second + 1)); + set intersection; + set_intersection(adj.begin(), adj.end(), boardKeys.begin(), boardKeys.end(), inserter(intersection, intersection.begin())); + set new_points; + set_difference(intersection.begin(), intersection.end(), path.begin(), path.end(), inserter(new_points, new_points.begin())); + if (dfs(new_points, s.substr(1), board, path, boardKeys)) + return true; + path.erase(it); + } + } + return false; +} + +class Solution +{ +public: + bool exist(vector> &board, string word) + { + // reverse the word + string rword = word; + reverse(rword.begin(), rword.end()); + + set points; // points to check for the next move + set boardKeys; // keys of the board, for checking for valid adjacent points + map board_map; // coordinate -> char map of the board + map board_char_count; // char -> count map of the board + for (uint i = 0; i < board.size(); i++) + { + for (uint j = 0; j < board[i].size(); j++) + { + points.insert(make_pair(i, j)); + board_map[make_pair(i, j)] = board[i][j]; + boardKeys.insert(make_pair(i, j)); + if (board_char_count.find(board[i][j]) == board_char_count.end()) + board_char_count[board[i][j]] = 1; + else + board_char_count[board[i][j]]++; + } + } + set path; + + map word_char_count; + for (uint i = 0; i < word.length(); i++) + { + if (word_char_count.find(word[i]) == word_char_count.end()) + word_char_count[word[i]] = 1; + else + word_char_count[word[i]]++; + } + + // check the case where any character in the word does not appear on the board + for (uint i = 0; i < word.size(); i++) + { + if (board_char_count.find(word[i]) == board_char_count.end()) + return false; + else if (board_char_count[word[i]] < word_char_count[word[i]]) + return false; + } + + // use word if the first character has less occurences than the reverse of the word + if (board_char_count[word[0]] > board_char_count[rword[0]]) + word = rword; + + return dfs(points, word, board_map, path, boardKeys); + } +}; \ No newline at end of file diff --git a/leetcode/solution.py b/leetcode/solution.py new file mode 100644 index 0000000..44b6ab7 --- /dev/null +++ b/leetcode/solution.py @@ -0,0 +1,45 @@ + +from itertools import product + +def search(points: set, s: str, board: dict, path: set = None) -> bool: + # points is a list of tuples (x, y) for points to try to connect to the first character of s + # s is the string to connect, check the list of points to see if they can be connected to form s + # board is the board of characters + # path is a list of points that have been used to connect to s so far + # return True if s can be connected, False otherwise + if path is None: + path = set() + if len(s) == 0: + return True + for p in points: + if s[0] == board[p]: + path.add(p) + # list of points left, right, up, down from p that are in the board keyset + adj = set([(p[0] + 1, p[1]), (p[0] - 1, p[1]), (p[0], p[1] + 1), + (p[0], p[1] - 1)]).intersection(board.keys()).difference(path) + if search(adj, s[1:], board, path): + return True + path.remove(p) + return False + +class Solution: + def exist(self, board: List[List[str]], word: str) -> bool: + # convert board to a dictionary of (x, y) -> character + board = {(x, y): board[x][y] for x, y in product( + range(len(board)), range(len(board[0])))} + + # if any char in the word is not in the board, return False + if not set(word).issubset(set(board.values())): + return False + + # if there are less occurences of the last character than the first character, reverse the word + boardstr = ''.join(board.values()) + if boardstr.count(word[0]) > boardstr.count(word[-1]): + word = word[::-1] + + # you take the input, and see if for each character, you can follow a path from character to character. The same character cannot be used more than once + return search( + set(board.keys()), + word, + board + ) \ No newline at end of file From 82fc104192e7da2e6c9f387b7750d9d58d2f89b4 Mon Sep 17 00:00:00 2001 From: Cole Fuerth Date: Fri, 2 Dec 2022 15:37:39 -0500 Subject: [PATCH 12/12] fill out pull request template --- .github/pull_request_template.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 30dd684..02daa3c 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -10,7 +10,7 @@ Cole Fuerth ## UWindsor Email -fuert11g@uwindsor.ca +[fuert11g@uwindsor.ca](mailto:fuert11g@uwindsor.ca) ## Application Form @@ -18,8 +18,15 @@ fuert11g@uwindsor.ca ## Briefly explain how your solution works and how to run it -My solution uses dfs to find the result. The first recursive call to `search()` includes the entire array as the possible set of starting points. For each call to `search()`, it trims the list to the points that match the first character of the word, then generates a valid list of adjacent points that have not been visited yet, and makes a recursive call to `search()` with the adjacent points, the word with the current character popped off, and the updated points visited so far. +### Brief -On **leetcode** (how I assume you are testing), this solution uses python3. You copy the body of the evaluate() function into exist() in leetcode, and copy my `import`s and `search()` function to the top of the script. +I first developed my solution in Python, then remade it in C++ for speed. **I would prefer the C++ solution to be considered, since it is considerably faster**, but it should still be noted that the Python solution came first, and runs almost as fast. The Python is also (understandably) much easier to read and understand, since the solutions are very much the same algorithmically. +### How it works -**Locally**, I am testing using `python3 solution.py < sample_input.txt`, where sample_input.txt contains the input. Input is read in on `stdin`, the way it is formatted in the problem statement. +My solution first tries to find exceptional cases that clearly will not fit first, then picks the better order of characters of the word (reversing the word will not change whether it fits the puzzle, and the order with the least starting points runs exponentially faster). Once it is known all the characters in the string appear on the board frequent enough to potentially fit, and that we have the optimal order of characters, a **depth first** approach is employed. Using sets to keep track of points, the board, and history, we can keep track of everything using set operations. `dfs` exhaustively tries all possible paths for the string, until eventually either fitting or exhausting all possibilities. + +### Running the code + +On **leetcode** (how I assume you are testing), you can copy and paste either of the solutions that are found under the **leetcode** folder directly onto the site. The C++ solution is in the top 1.5% of submissions; the Python solution is in the top 10% for runtime. + +**Locally**, I am testing using `make` with the provided Makefile, or `python3 solution.py`. The test case is hard coded into `main` on each of the source files in the root directory.