競技プログラマ向け 形式言語理論 入門 稲葉 一浩 JOI 春合宿 2012.

Slides:



Advertisements
Similar presentations
ACM/ICPC と アルゴリズム 「実践的プログラミング」 稲葉 一浩. 自己紹介 ﻪ 理Ⅰ → 理学部情報科学科 → 情報理工学系研究科コンピュータ科学専攻 ﻩ 博士課程1年 ﻩXML を扱う専用言語の研究など ﻪ 個人的には ﻩ ﻯD.
Advertisements

プログラミング言語論 第3回 BNF 記法について(演習付き) 篠埜 功. 構文の記述 プログラミング言語の構文はどのように定式化できるか? 例1 : for ループの中に for ループが書ける。 for (i=0; i
0章 数学基礎.
和田俊和 資料保存場所 /2/26 文法と言語 ー正規表現とオートマトンー 和田俊和 資料保存場所
プログラミング言語論 第10回(演習) 情報工学科 木村昌臣   篠埜 功.
Problem J: いにしえの数式 問題作成・解説: 北村 解答作成協力: 八森.
2行+αチョンプに関する考察 京都大学 ○後藤順一 伊藤大雄.
正規表現からのDFA直接構成.
7/10 if 文課題 力作が多くて感心! 演習1:キーボードから2つの整数を入力し、小さい方の数字を 表示せよ。
富山大学 公開講座 2008 「QRコードを作ろう!」 ~ QRコードを作ろう! ~.
データ構造と アルゴリズム 第十二回 知能情報学部 知能情報学科 新田直也.
情報・知能工学系 山本一公 プログラミング演習Ⅱ 第4回 配列(2) 情報・知能工学系 山本一公
コンパイラ 2011年10月17日
第11回 整列 ~ シェルソート,クイックソート ~
基礎プログラミングおよび演習 第9回
Permutationグラフと Distance-Hereditaryグラフの 再構築アルゴリズム
データ構造と アルゴリズム 第二回 知能情報学部 新田直也.
模擬国内予選2014 Problem C 壊れた暗号生成器
プログラミング論 II 電卓,逆ポーランド記法電卓
コンパイラ 2012年10月15日
10.通信路符号化手法2 (誤り検出と誤り訂正符号)
二分探索木によるサーチ.
形式言語とオートマトン2013 ー有限オートマトンー 第5日目
形式言語とオートマトン2008 ー有限オートマトンー
プログラミング言語論 第3回 BNF記法について(演習付き)
正則言語 2011/6/27.
形式言語の理論 5. 文脈依存言語.
東京工科大学 コンピュータサイエンス学部 亀田弘之
プログラミング 4 記憶の割り付け.
アルゴリズムとプログラミング (Algorithms and Programming)
形式言語とオートマトン Formal Languages and Automata 第4日目
“Separating Regular Languages with First-Order Logic”
プログラミング演習I 2003年5月7日(第4回) 木村巌.
1. 集合 五島 正裕.
第3回 アルゴリズムと計算量 2019/2/24.
平成20年10月5日(月) 東京工科大学 コンピュータサイエンス学部 亀田弘之
計算の理論 II 前期の復習 -有限オートマトン-
東京工科大学 コンピュータサイエンス学部 亀田弘之
2007年度 情報数理学.
プログラミングⅠ 平成31年1月7日 森田 彦.
プログラミング言語論 第9回 情報工学科 木村昌臣 篠埜 功.
生物情報ソフトウェア特論 (2)たたみ込みとハッシュに 基づくマッチング
ナップサック問題 クマさん人形をめぐる熱いドラマの結末.
平成26年4月22日(火) 東京工科大学 コンピュータサイエンス学部 亀田弘之
計算の理論 I ー正則表現とFAの等価性 その1ー
計算の理論 I 決定性有限オートマトン(DFA) と 非決定性有限オートマトン(NFA)
JavaScriptを含んだHTML文書に対する データフロー解析を用いた構文検証手法の提案
補講:アルゴリズムと漸近的評価.
第16章 動的計画法 アルゴリズムイントロダクション.
計算の理論 I -数学的概念と記法- 火曜 12:50~14:20 大月 美佳 2004年4月20日.
5.チューリングマシンと計算.
計算の理論 I ー正則表現とFAの等価性ー 月曜3校時 大月 美佳.
アルゴリズムとデータ構造1 2009年6月15日
計算の理論 I -数学的概念と記法- 月曜3校時 大月 美佳.
第5章 まだまだ続く反復処理!! ~繰り返しその2 for~
4.プッシュダウンオートマトンと 文脈自由文法の等価性
情報処理Ⅱ 第7回 2004年11月16日(火).
東京工科大学 コンピュータサイエンス学部 亀田弘之
発表者: 稲葉 一浩 複雑ネットワーク・地図グラフ セミナー 2017/1/19
計算の理論 I ー 正則表現 ー 月曜3校時 大月 美佳.
コンパイラ 2012年10月11日
アルゴリズムとデータ構造 2010年6月17日
参考:大きい要素の処理.
形式言語とオートマトン Formal Languages and Automata 第5日目
情報生命科学特別講義III (3)たたみ込みとハッシュに 基づくマッチング
情報処理Ⅱ 2005年11月25日(金).
復習 いろいろな変数型(2) char 1バイト → 英数字1文字を入れるのにぴったり アスキーコード → 付録 int
C言語講座 四則演算  if ,  switch 制御文.
7.集合 7.1 集合とは [集合と要素] 関東の都道府県 群馬県 栃木県 要素 埼玉県 茨城県 東京都 千葉県 神奈川県
計算機プログラミングI 第5回 2002年11月7日(木) 配列: 沢山のデータをまとめたデータ どんなものか どうやって使うのか
Presentation transcript:

競技プログラマ向け 形式言語理論 入門 稲葉 一浩 JOI 春合宿 2012

文字列やツリーやグラフの 集合 について考える分野 「形式言語理論」とは 文字列やツリーやグラフの 集合 について考える分野

文字列やツリーやグラフの 集合 を、どうやって表現するか について考える分野 「形式言語理論」とは 文字列やツリーやグラフの 集合 を、どうやって表現するか について考える分野

文字列やツリーやグラフの 集合 を、どうやって表現するか について考える分野 「形式言語理論」とは 今日は 文字列の集合だけ 扱います 文字列やツリーやグラフの 集合 を、どうやって表現するか について考える分野

文字列やツリーやグラフの 集合 を、表現するデータ構造 について考える分野 「形式言語理論」とは 文字列やツリーやグラフの 集合 を、表現するデータ構造 について考える分野

std::set<std::string> #include <set> #include <string> std::set<std::string> ?

文字列やツリーやグラフの 無限かもしれない集合 の、有限のメモリでの表現 について考える分野 「形式言語理論」とは 文字列やツリーやグラフの 無限かもしれない集合 の、有限のメモリでの表現 について考える分野

文字列の無限集合の例 {“”, “a”, “aa”, “aaa”, “aaaa”, ...} 「長さが偶数の文字列すべて」 「回文じゃない文字列」 「円周率の10進表記の部分列」 ・・・

ここからの話題 いくつかの表現方法の紹介 どんな操作が可能か (コンテストっぽい)応用 (夢の広がる)応用

文字列集合を 有向グラフで表現

{“a”, “ba”, “bba”, ...} a b b S G a 「aが奇数個」

{“”, “aa”, “ab”, “b”, “bab”, ...} G a b b b b SG G a b a 「aで始まって長さ2以上、  またはbで始まってbで終わる」

グラフで表す文字列集合 G a SG b 辺に文字が書いてある 各頂点には が付いているかも S という印 G という印 S と G 両方  が付いているかも SG a b G こういうグラフを、 「SからGまでの経路になってる文字列すべて」 という集合を表していると考えます。

こんな集合が表せる S G 有限集合は全部書ける 「特定の文字列を部分に含む文字列ぜんぶ」 「aとbが交互に繰り返し出てくる文字列」 root が 、leaf が の tree で表現する 「特定の文字列を部分に含む文字列ぜんぶ」 KMP法、 Aho-Corasick法 「aとbが交互に繰り返し出てくる文字列」 ループっぽいものはグラフでサイクルを作ると書ける 書けないものもあります。 「回文」 「括弧の対応が取れてる文字列」 S G

2つの流儀: DFA と NFA Deterministic Finite Automaton Nondeterministic Finite Automaton S が 1 つ 一つの頂点から出る、 同じ文字の辺は1本以下 なんでもあり 文字無し辺もOKとする事も S G a b “” S G a b

できる操作の、ごく一部 (だいたい思いつく物はなんでもできます) bool contains(Automaton a, String w); 与えられた文字列を含むかの判定 Automaton complement(Automaton a); 補集合の計算 Automaton intersect(Automaton a, Automaton b); 共通部分の計算 Automaton equals(Automaton a); 集合として等しい?

bool contains(DFA a, String w); DFAの場合 一つの頂点から出る、 同じ文字の辺は1本以下 S G a b Node v = a.S; //Sは1つなので始点は1つに決まる foreach(char c : w) v = a.next(v, c); //文字が決まれば辺も1つ return v.isG();

bool contains(NFA a, String w); NFAの場合 少しだけ難しい 問題: S から G まで、文字列 w に 合わせて動いてたどり着く 道はあるか? S G a b “”

bool contains(NFA a, String w); NFAの場合 解法1 : DP bool[頂点数][文字列長+1] S1 G S2 a b “” “a b b a” S1 ○ S2 G

bool contains(NFA a, String w); NFAの場合 解法1 : DP bool[頂点数][文字列長+1] S1 G S2 a b “” “a b b a” S1 ○ × S2 G

bool contains(NFA a, String w); NFAの場合 解法1 : DP bool[頂点数][文字列長+1] S1 G S2 a b “” “a b b a” S1 ○ × S2 G

bool contains(NFA a, String w); NFAの場合 解法1 : DP O( |edge|・|w| ) S1 G S2 a b “” “a b b a” S1 ○ × !!○!! S2 G

bool contains(NFA a, String w); NFAの場合 解法2 : ビットDP ○○×○  2進法で “1101” とビットにエンコードできる int [文字列長さ+1] “a b b a” S1 ○ × !!○!! S2 G 1101 0011 1000

bool contains(NFA a, String w); NFAの場合 ・・・ 解法3 : ビットDP & 前処理 O( 2|node| + |w| ) a G 0011 a “a b b a” SG 1101 b S1 ○ × !!○!! 1000 S2 b G 0011 a G b 1101 0011 1000 ・・・

解法3のポイント NFA を DFA に変換してから処理している NFA の表現力 = DFA の表現力 サイズは指数でふくらみますが…

できる操作その他 bool contains(Automaton a, String w); 与えられた文字列を含むかの判定 Automaton complement(Automaton a); 補集合の計算 Automaton intersect(Automaton a, Automaton b); 共通部分の計算 Automaton equals(Automaton a); 集合として等しい?

集合と集合の共通部分 Automatonで表現した 集合 a と集合 b の 共通部分 を表す Automaton の求め方

頂点と頂点のペアを作る b a 1 b a 3 4 a a 2 b b 1,3 1,4 2,3 2,4

頂点と頂点のペアを作る b a 1 b a 3 4 a a 2 b b 1,3 1,4 2,3 2,4 b なので a 2,3 2,4

頂点と頂点のペアを作る b a 1 b a 3 4 a a 2 b b b 1,3 1,4 a a 2,3 2,4 b

両方SならSに 両方GならGに b a 1 b a 3 4 a a 2 b b 1,3 1,4 2,3 2,4 b a a b 「長さが奇数」 「aが奇数個」 b 1,3 1,4 a a 「aが奇数個かつ  長さが奇数」 2,3 2,4 b

和集合 どちらかがGならGに b a 1 b a 3 4 a a 2 b b 1,3 1,4 2,3 2,4 b a a b 「長さが奇数」

できる操作その他 集合の補集合 空集合かどうか判定 集合の包含関係 (A⊆B; A が完全にBに含まれているか?) 集合が等しいかどうか DFA なら G と Gじゃない頂点を反転するだけ NFA は DFA に変換してください 空集合かどうか判定 S から G に到達可能か判定するだけ 集合の包含関係 (A⊆B; A が完全にBに含まれているか?) 「((Bの補集合)と A の共通部分)が空集合か?」と同じ 集合が等しいかどうか A⊆B && B⊆A  (もっと効率よく判定もできます)

練習問題: “Double Meaning” 1~N の自然数を、それぞれ長さ M 以下のビット列に変換して 自然数のリストを表現することにした。例えば右下の変換表を使うと [3,1,2] が になる。 ところがこの変換表は困りもので、 [3,3,3] も になるし [1,2,3] も になってしまう。 変換表を受け取って、こういう困ったこと(違うリストが 同じビット列になってしまう)が起こるかどうか判定せよ。(N,M≦50) 100100100 1 → 1001 2 → 00 3 → 100 100100100 100100100

想定誤答 1 → 1001 2 → 00 3 → 100 for(int i=0; i<code.size(); ++i) “100” が “1001” の prefix なのが問題。 これじゃ前から読んでってどちらか区別できない for(int i=0; i<code.size(); ++i) for(int j=0; j<code.size(); ++j) if(i!=j && code[i].is_prefix(code[j])) return BAD; return GOOD;

撃墜例 この変換表は一意に復元可能 1 → 1 2 → 10 3 → 001

解答例 (もっと効率いい解法はありそう…) 集合を使います for(int i=0; i<code.size(); ++i) if( 「iから始まるリストの変換結果の集合」 と 「i以外から始まるリストの変換結果の集合」 の共通部分が空集合ではない ) return BAD; return GOOD;

1 1 → 1001 2 → 00 3 → 100 1 1 1 S G 1 「[1,...]で始まるリストの変換結果」 1 1 S G 1 S 1 「[2,...]か[3,...]で始まるリストの変換結果」

できる操作その他 集合の補集合 空集合かどうか判定 集合の包含関係 (A⊆B; A が完全にBに含まれているか?) 集合が等しいかどうか DFA なら G と Gじゃない頂点を反転するだけ NFA は DFA に変換してください 空集合かどうか判定 S から G に到達可能か判定するだけ 集合の包含関係 (A⊆B; A が完全にBに含まれているか?) 「((Bの補集合)と A の共通部分)が空集合か?」と同じ 集合が等しいかどうか A⊆B && B⊆A  (もっと効率よく判定もできます)

その他にできること: DFAの最小化 S G a b 実は 表してる集合は 同じ! S G a b a 「aが奇数個」

DFA最小化の嬉しいところ O(|edge| log |node|) でできる。 最小化するとグラフの形が一つに定まる。 集合の = の判定が簡単 共通部分や和集合やNFA→DFA変換は 無駄に大きいDFAを作ることが多いので、 小さくするのが実用上は必須。

最小化のアルゴリズム a b a G b S G b a a b 方針: どんな文字列 w についても、 「頂点 v から w に沿って進んだ先が G」 if and only if 「頂点 u から w に沿って進んだ先が G」 なら、 v と u はマージする S G b a a b

最小化のアルゴリズム a b G a b 「G な頂点」  と 「G じゃない頂点」 はマージできないので 別グループ S G b a a b

最小化のアルゴリズム a b G a b S G  注目! b a a b

最小化のアルゴリズム a b a G b S G b a a b 文字 ‘a’ で進んだら に入る頂点たちと そうじゃない頂点は マージ不可能 a a b

最小化のアルゴリズム a b G a b S G よって分離。 b a a b

最小化のアルゴリズム a b a G b S G b a a b 文字 ‘b’ でも 同じことを繰り返す。 分割が起きた場合は、 分かれてできたグループ を両方(元   を使用済みの場合は小さい方)を使い同様に分割を繰返す b S G b a a b

最小化のアルゴリズム a b G a 収束したら終了 マージする。 b S G a b b G a a b a S G b b a

最小化のアルゴリズム 最初の分割 次の分割 ... というループなので、収束するまでやれば正しい 0文字で G と Gじゃないところに分かれる頂点を分離 次の分割 1文字で G と Gじゃないところに分かれる頂点を分離 ... というループなので、収束するまでやれば正しい        を分割に使っていれば      は小さい方だけ     使う、というところだけ工夫

その他にできること: セグメント木に載せる 問題 DFA a (頂点数≦20) 文字列 w (長さ≦10万) 0≦ i < k ≦ |w| な自然数の組が1万個 w[i, k) が DFA の表す集合に入っているか それぞれ判定せよ

a b b a a b a b 1 2 3 4 b a a b 14 23 32 41 12 21 34 43 12

b 1 2 a a 3 4 b 1  3 2  4 3  1 4  2 1  3 2  4 3  1 4  2 1  3 2  4 3  1 4  2 1  3 2  4 3  1 4  2 14 23 32 41 12 21 34 43 12 21 34 43 14 23 32 41 14 23 32 41 12 21 34 43 14 23 32 41 12 21 34 43 a b b a a b a b

b 1 2 1  1 2  2 3  3 4  4 a a 3 4 1  1 2  2 3  3 4  4 1  1 2  2 3  3 4  4 b 1  3 2  4 3  1 4  2 1  3 2  4 3  1 4  2 1  3 2  4 3  1 4  2 1  3 2  4 3  1 4  2 14 23 32 41 12 21 34 43 12 21 34 43 14 23 32 41 14 23 32 41 12 21 34 43 14 23 32 41 12 21 34 43 a b b a a b a b

b 1 2 1  1 2  2 3  3 4  4 a a 3 4 1  1 2  2 3  3 4  4 1  1 2  2 3  3 4  4 b 1  3 2  4 3  1 4  2 1  3 2  4 3  1 4  2 1  3 2  4 3  1 4  2 1  3 2  4 3  1 4  2 14 23 32 41 12 21 34 43 12 21 34 43 14 23 32 41 14 23 32 41 12 21 34 43 14 23 32 41 12 21 34 43 a b b a a b a b

※詳しくはWebで! Factorization Forest DFA・NFA の場合、Segment Tree の替わりに というテクニックで 同じ機能のものが定数高さの木でできます。

練習問題 AOJ 2017 AOJ 1169 Topcoder SRM378 Div1 Hard Topcoder TCO’09 Semifinal Medium

おまけ: 形式言語理論の未解決問題 Cerný 予想 a DFAを 考える b b a a b a どの頂点に いても baaabaaab と歩くと… a b

Cerný 予想 a baaabaaab b b a a b a a b と歩くと… 必ず同じ点に着きます このDFAの 同期語 といいます。 a b

Cerný 予想 a b a b NP 困難 問題: N 頂点の DFA が与えられる。 最短の同期語の長さを求めよ。 存在しない場合は -1 を返せ a b a b NP 困難

予想: 同期語が存在するなら、 長さは必ず (N-1)2 以下である。 ≪Cerný 予想≫ 予想: 同期語が存在するなら、 長さは必ず (N-1)2 以下である。 Jan Cerný, 1964

文字列集合を 論理式で表現

b_after_a(string s) := forall i in indices(s) if s[i]==‘a’ then exists j in indices(s) i≦j and s[j]==‘b’ 「aが出たら後でbも出る」

even_A(string s) := exists A ⊆ indices(s) forall i in indices(s) if i in A then s[i]==‘a’ else s[i]!=‘a’ & |A| mod 2 = 0 「aが偶数個」

(詳細略) (紹介だけ) and, or, not , if ~ then (添え字に関する) forall (添え字に関する) exists (添え字の集合に関する) forall (添え字の集合に関する) exists mod 定数 で数をカウント すべて Automaton に変換できることが 知られています

文字列集合を パターンで表現

正規表現 b*ab*(ab*ab*)* a(a|b)(a|b)* | b((a|b)*b)? Perl, Ruby, Java 等での 普通のプログラミングでよく使います。 b*ab*(ab*ab*)* 「aが奇数個」 a(a|b)(a|b)* | b((a|b)*b)? 「aで始まって長さ2以上、  またはbで始まってbで終わる」

正規表現の使用例

正規表現 hoge | fuga hoge* hoge? hoge の表す集合と fuga の表す集合の和集合

NFA で 表せます hoge* の例 a a G a b b b b SG G a b a

NFA で 表せます hoge* の例 a a G a b “” b “” S G b “” b SG G “” a “” b a

逆に、Automaton は すべて正規表現で書けます foreach(i : nodes) d[i][i] = 0; foreach(i--c-->j : edges) d[i][j] = c; foreach(k : nodes) foreach(j : nodes) d[i][j] = min( d[i][j], d[i][k]+d[k][j]); 方針: Warshall-Floyd 1 2 a b

逆に、Automaton は すべて正規表現で書けます foreach(i : nodes) d[i][i] = “”; foreach(i--c-->j : edges) d[i][j] = d[i][j] | c; foreach(k : nodes) foreach(j : nodes) d[i][j] = d[i][j] | d[i][k] d[k][k]* d[k][j]; 方針: Warshall-Floyd 1 2 a b

おまけ: 形式言語理論の未解決問題Star-Height 問題 さっきの「Automaton→正規表現」変換は * を使いすぎる。もっと減らせないか? | (和集合), * (繰り返し) の他に & (積集合), ¬(補集合), Φ (空集合) も使う正規表現を 一般正規表現という b*ab*(ab*ab*)* 「aが偶数個、  じゃない」 「aが奇数個」 ¬((¬(¬Φa¬Φ)a¬(¬Φa¬Φ)a¬(¬Φa¬Φ))*)

* のネストなしで、Automatonを 全て一般正規表現で表せるか? ≪Star-Height 問題≫ * のネストなしで、Automatonを 全て一般正規表現で表せるか? Janusz Brzozowski, 1980

文字列集合を 文法で表現

{“1+2*3/(4-5)”, “0*0*0+0”, ...} EXPR ::= TERM | TERM “+” TERM TERM ::= FACTOR “*” FACTOR | FACTOR “/” FACTOR FACTOR ::= “(“ EXPR “)” | “0” | “1” | ... | ”9” 「一桁の数の四則演算式」

{“”, “a”, “b”, “aa”, “aba”, ...} PALINDROME ::= “a” | “b” | “” | “b” PALINDROME “b” 「回文」

文脈自由文法 Context Free Grammar 例) PALINDROME ::= “a” | “b” | “” | “a” PALINDROME “a” | “b” PALINDROME “b” PALIN → “a” PALIN “a” → “a” “b” PALIN “b” “a” → “a” “b” “a” PALIN “a” “b” “a” → “a” “b” “a” “” “a” “b” “a” → “abaaba” 左辺 ::= 右辺 | 右辺 | ... | 右辺 という規則の集まりを、 「左辺の記号を右辺のどれかに書き換え」を 繰り返したら作れる文字列の集合、と見なします。

bool contains(CFG g, string w); 右辺の長さが 2以下になるように 変形してから・・・ P ::= “” | “a” | “b” | “a” Q | “b” R Q ::= P “a” R ::= P “b” P ::= “” | “a” | “b” | “a” P “a” | “b” P “b”

bool contains(CFG g, string w); 右辺の長さが 2以下になるように 変形してから・・・ P ::= “” | “a” | “b” | “a” Q | “b” R Q ::= P “a” R ::= P “b” 動的計画法。O ( |g| |w|3 )。 bool dp[左辺記号][i][k] = “左辺記号” から w[i .. k)   が作れるか?

bool contains(CFG g, string w); (オーダーの意味で)世界最速は2012年3月現在 O ( |g|・|w| 2.3723 ) だそうです。 行列の掛け算と同じオーダです。

ほかの集合演算は? 空集合かどうかの判定  できる(簡単) 和集合の計算  できる(簡単) 共通部分 補集合 空集合かどうかの判定  できる(簡単) 和集合の計算  できる(簡単) 共通部分 CFG と CFG の共通部分は CFG では書けない! 補集合 CFG の補集合は CFG では書けない! 等しさ = の判定、 包含関係 ⊆ の判定 決定不能!

http://hos.ac/slides/ から引用

Postの対応問題ゲーム http://d.hatena.ne.jp/ku-ma-me/20100724/p1

「2つのCFGの共通部分が空か?」は 決定不能 A  a1 A “1” | a2 A “2” ... | ar A “r” | “$” B  b1 B “1” | b2 B “2” ... | br B “r” | “$”

演算はあまりサポートしない CFG と CFG の共通部分の空判定は決定不能 CFG が文字列全部を表してるかの判定は 決定不能 (証明略) 空判定はできるので、Post の対応問題が解けちゃう CFG が文字列全部を表してるかの判定は 決定不能 (証明略)  CFG の補集合は CFG で書けない  CFG =? CFG や CFG ⊆? CFG は決定不能 CFG と DFA の共通部分は計算可能  CFG ⊆? DFA は判定可能

文字列検索/解析以外への 【応用事例】

文字列の「型」に使う string<(a|b)(a|b)*> s; s = “”; //コンパイルエラー! 和集合や文字列結合を使って、演算結果の型を計算 集合の包含判定を使って、型キャストのチェック string<(a|b)(a|b)*> s; s = “”; //コンパイルエラー! s = “c” ; //コンパイルエラー! string<(a|b)(a|b)(a|b)*> t = s; //エラー! string<(a|b)(a|b)(a|b)*> u = s+s; //OK!

プログラムが正しい順で 関数を呼ぶことの検証 File file = new File(“input.txt”); solve(file); void solve(File file) { int T = file.ReadInt(); solveCases(T, file); } void solveCases(int N, File file) { if(N == 0) file.Close(); else {String s = file.ReadLine(); // solve here... solveCases(N-1, file); } }

プログラムが正しい順で 関数を呼ぶことの検証 File file = new File(“input.txt”); solve(file); void solve(File file) { int T = file.ReadInt(); solveCases(T, file); } void solveCases(int N, File file) { if(N == 0) file.Close(); else {String s = file.ReadLine(); // solve here... solveCases(N-1, file); } } プログラムの挙動 MAIN ::= “new” SOLVE SOLVE ::= “readint” CASES CASES ::= “close” | “readline” CASES

プログラムが正しい順で 関数を呼ぶことの検証 File file = new File(“input.txt”); solve(file); void solve(File file) { int T = file.ReadInt(); solveCases(T, file); } void solveCases(int N, File file) { if(N == 0) file.Close(); else {String s = file.ReadLine(); // solve here... solveCases(N-1, file); } } ファイルは この順で 操作しないとダメ! “new” (“readint” | “readline”)* “close” プログラムの挙動 MAIN ::= “new” SOLVE SOLVE ::= “readint” CASES CASES ::= “close” | “readline” CASES

プログラムが正しい順で 関数を呼ぶことの検証 File file = new File(“input.txt”); solve(file); void solve(File file) { int T = file.ReadInt(); solveCases(T, file); } void solveCases(int N, File file) { if(N == 0) file.Close(); else {String s = file.ReadLine(); // solve here... solveCases(N-1, file); } } CFG ⊆? DFA は 決定可能 “new” (“readint” | “readline”)* “close” ⊆ ? MAIN ::= “new” SOLVE SOLVE ::= “readint” CASES CASES ::= “close” | “readline” CASES

自然数の集合を表す (2進数表記を下位ビットから並べた文字列として) 1 G 「2の倍数」 1 SG 1 SG G 1 「3の倍数」

自然数のペアやn個組の集合 (nビットを一文字として) (16, 7) → (10000, 00111) → “00001 11100” 「偶数と、3 mod 4 の数のペア」 1 1 S G なんでも 1

いろいろな演算 Automaton で自然数の もちろん なども・・・ などが定義できる 大小関係 足し算 固定幅ビットシフト 定数での mod などが定義できる もちろん 和集合 共通部分 なども・・・

こんな集合が表現できます。幾何!

まとめ まとめ

まとめ G S a b 文字列の(無限)集合の幾つかの表現方法を紹介しました 色々な集合演算の を紹介しました。 有向グラフで表現する 論理式で表現する パターンで表現する 文法で表現する 色々な集合演算の 実装方法 応用  を紹介しました。 S G a b “”