文字数は1~6なので 同じ本数の枝を持つパスで生成される呪文の長さは最大で6 倍の差がある 例えば 上図のようなケースを考える 1サイクル終了した時点では スター節点のところに最強呪文として aaaaaac が求まる しかしながら サイクルを繰り返していくと やがてスター節点のところに aaaaaa

Similar documents
[Problem F] 古い記憶 良さそうな方法は思いつかなかった アイディア募集中!!! かなり強引に解いている 各判定データに対して 30 秒程度かかる 元の文章と改ざん文章の関係を考える ウィルス感染の可能性は高々 2 回であり 各々の感染では 1 文字削除 1 文字追加 1 文字変更が行われ

プログラム例 /* ACM-ICPC2009 国内予選 Problem C */ // // filename = pc1.c // コンパイル

ープのロープ長以下であれば実現可能である ケース 3: 3 本のロープの杭の位置を点 P 1 = (x 1, y 1, 0), 点 P 2 = (x 2, y 2, 0), 点 P 3 = (x 3, y 3, 0) とする 点 P 1 = (x 1, y 1, 0), 点 P 2 = (x 2,

Taro-スタック(公開版).jtd

Taro-リストⅢ(公開版).jtd

[Problem D] ぐらぐら 一般に n 個の物体があり i 番目の物体の重心の x 座標を x i, 重さを w i とすると 全体の n 重心の x 座標と重さ w は x = ( x w ) / w, w = w となる i= 1 i i n i= 1 i 良さそうな方法は思いつかなかった

PowerPoint プレゼンテーション

Taro-再帰関数Ⅱ(公開版).jtd

Taro-2分探索木Ⅱ(公開版).jtd

プログラミング基礎

Prog1_10th

第86回日本感染症学会総会学術集会後抄録(I)

PowerPoint プレゼンテーション

次に示す数値の並びを昇順にソートするものとする このソートでは配列の末尾側から操作を行っていく まず 末尾の数値 9 と 8 に着目する 昇順にソートするので この値を交換すると以下の数値の並びになる 次に末尾側から 2 番目と 3 番目の 1

Microsoft Word - ICPC2014_DomG.docx

r07.dvi

ohp07.dvi

プログラミング方法論 II 第 14,15 回 ( 担当 : 鈴木伸夫 ) 問題 17. x 座標と y 座標をメンバに持つ構造体 Point を作成せよ 但し座標 は double 型とする typedef struct{ (a) x; (b) y; } Point; 問題 18. 問題 17 の

ポインタ変数

untitled

PowerPoint プレゼンテーション

Microsoft Word - no12.doc

memo

Microsoft PowerPoint - ad11-09.pptx

第2回

Taro-2分探索木Ⅰ(公開版).jtd

PowerPoint プレゼンテーション

ポインタ変数

バイオプログラミング第 1 榊原康文 佐藤健吾 慶應義塾大学理工学部生命情報学科

Java講座

: CR (0x0d) LF (0x0a) line separator CR Mac LF UNIX CR+LF MS-DOS WINDOWS Japan Advanced Institute of Science and Technology

Microsoft PowerPoint - lec10.ppt

Microsoft Word - Cプログラミング演習(12)

PowerPoint プレゼンテーション

1. 入力した文字列を得る 1.1. 関数 scanf() を使う まずは関数 scanf() を使ったプログラムを作ってみましょう 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: #include<stdio.h> #define SIZE 128 main(

DA13

Microsoft Word - no11.docx

第2回

< F2D837C E95CF CF68A4A94C5816A2E6A>

Taro-再帰関数Ⅲ(公開版).jtd

本サンプル問題の著作権は日本商工会議所に帰属します また 本サンプル問題の無断転載 無断営利利用を厳禁します 本サンプル問題の内容や解答等に関するお問 い合わせは 受け付けておりませんので ご了承ください 日商プログラミング検定 STANDARD(C 言語 ) サンプル問題 知識科目 第 1 問 (

1. 入力した正の整数を降順に並べ換えて出力するプログラムを作成せよ プログラムは個別にコンパイルし make コマンドで実行すること 入力データは 50 以下とし 以下の数が混在しているとする 16 進数 : 先頭 1 文字が x または X( エックスの小文字か大文字 ) 8 進数 : 先頭 1

Microsoft PowerPoint - 05.pptx

Microsoft Word - no103.docx

RX ファミリ用 C/C++ コンパイラ V.1.00 Release 02 ご使用上のお願い RX ファミリ用 C/C++ コンパイラの使用上の注意事項 4 件を連絡します #pragma option 使用時の 1 または 2 バイトの整数型の関数戻り値に関する注意事項 (RXC#012) 共用

日本内科学会雑誌第98巻第4号

日本内科学会雑誌第97巻第7号

ohp03.dvi

Taro-最大値探索法の開発(公開版

プログラミングI第10回

Prog1_15th

PowerPoint Presentation

1 1.1 C 2 1 double a[ ][ ]; 1 3x x3 ( ) malloc() 2 double *a[ ]; double 1 malloc() dou

4 分岐処理と繰返し処理 ( 教科書 P.32) プログラムの基本的処理は三つある. (1) 順次処理 : 上から下に順番に処理する ぶんきそろ (2) 分岐処理 : 条件が揃えば, 処理する はんぷく (3) 反復処理 : 条件が揃うまで処理を繰り返す 全てのプログラムは (1) から (3) の

Microsoft Word - Cプログラミング演習(8)

Microsoft Word - no13.docx

program7app.ppt

Microsoft Word - Cプログラミング演習(9)

Microsoft Word - no206.docx

Taro-リストⅠ(公開版).jtd

Microsoft Word - no15.docx

Prog1_6th

Microsoft Word - Cプログラミング演習(10)

Microsoft Word - 13

コマンドラインから受け取った文字列の大文字と小文字を変換するプログラムを作成せよ 入力は 1 バイトの表示文字とし アルファベット文字以外は変換しない 1. #include <stdio.h> 2. #include <ctype.h> /*troupper,islower,isupper,tol

Microsoft Word - Training10_プリプロセッサ.docx

Microsoft PowerPoint pptx

1 1.1 C 2 1 double a[ ][ ]; 1 3x x3 ( ) malloc() malloc 2 #include <stdio.h> #include

PowerPoint プレゼンテーション

Microsoft PowerPoint - CproNt02.ppt [互換モード]

II 3 yacc (2) 2005 : Yacc 0 ~nakai/ipp2 1 C main main 1 NULL NULL for 2 (a) Yacc 2 (b) 2 3 y

memo

r08.dvi

Taro-ポインタ変数Ⅰ(公開版).j

Microsoft Word - 3new.doc

Microsoft Word - 第5回 基本データ構造2(連結リスト).doc

memo

Microsoft PowerPoint - kougi10.ppt

memo

ohp08.dvi

始めに, 最下位共通先祖を求めるための関数 LcaDFS( int v ) の処理を記述する. この関数は値を返さない再帰的な void 関数で, 点 v を根とする木 T の部分木を深さ優先探索する. 整数の引数 v は, 木 T の点を示す点番号で, 配列 NodeSpace[ ] へのカーソル

r03.dvi

memo

O(N) ( ) log 2 N

file"a" file"b" fp = fopen("a", "r"); while(fgets(line, BUFSIZ, fp)) {... fclose(fp); fp = fopen("b", "r"); while(fgets(line, BUFSIZ, fp)) {... fclose

C プログラミング演習 1( 再 ) 2 講義では C プログラミングの基本を学び 演習では やや実践的なプログラミングを通して学ぶ

Microsoft PowerPoint - 11.pptx

Microsoft PowerPoint - 4.pptx

gengo1-12

memo

問 2 ( 型変換 ) 次のプログラムを実行しても正しい結果が得られない 何が間違いかを指摘し 正しく修正せよ ただし int サイズが 2 バイト long サイズが 4 バイトの処理系での演算を仮定する #include <stdio.h> int main( void ) { int a =

kiso2-09.key

I. Backus-Naur BNF : N N 0 N N N N N N 0, 1 BNF N N 0 11 (parse tree) 11 (1) (2) (3) (4) II. 0(0 101)* (

02: 変数と標準入出力

Microsoft Word - no202.docx

新版明解C言語 実践編

Taro-プログラミングの基礎Ⅱ(公

n 2 + π2 6 x [10 n x] x = lim n 10 n n 10 k x 1.1. a 1, a 2,, a n, (a n ) n=1 {a n } n=1 1.2 ( ). {a n } n=1 Q ε > 0 N N m, n N a m

通信プログラムの試作ーーー UDP を用いたじゃんけんゲームシステム ーーーー裘彬濱 南山大学情報理工学部 ソフトウェア工学科青山研究室

Microsoft PowerPoint - 15Game.ppt

Transcription:

[Problem E] 最強の呪文 例えば 上図のような場合を考えると 節点 0( スター ) から節点 1 に至るパスの最強の呪文は aa であるが 節点 0 から節点 2 に至るパスの最強の呪文は aabc であり 節点 0 と節点 1 の間のパスとして最強の aa は用いられていない したがって スターから各節点への最強の呪文を求めていく方法は旨く機能しないと考えられる 一方 上図において 節点 2 から節点 3( ゴールド ) に至るパスの最強の呪文は cde であり 節点 1 から節点 2 を経由して節点 3 に至るパスの最強呪文は aacde であり 節点 2 と節点 3 の間のパスとして最強の cde が用いられている したがって 各節点からゴールドに至るパスの最強呪文をパスを構成する枝数の順に求めていけば スターからゴールドにいたるパスの最強呪文を求めることができる ( 存在する場合 ) スター 0 α β ゴールド 1 γ 2 最強の呪文が存在する場合 その呪文にはループは含まれない もし上図のようなループを含んでいるとすると αβγ の方が αγ より強い事を意味し その場合 αβ βγ は αβγ より強くなる したがってループを回る回数を増やすことによりいくらでも強い呪文を作ることができ 最強の呪文は存在しなくなる これらの考察より 節点数を n とするときに 枝の本数を 1 から n 1 まで順次増やしながら 指定の枝の本数以下のパスを対象として 各節点からゴールドにいたるパスの中での最強の呪文を求めていく これにより最強の呪文が存在する場合は ループ無しの最強呪文が スター 節点のところに求まっている プログラム例では この操作を1サイクルと呼んでいる 最強の呪文が存在するかどうかについては もう少し検討が必要である 各枝のラベルの 1

文字数は1~6なので 同じ本数の枝を持つパスで生成される呪文の長さは最大で6 倍の差がある 例えば 上図のようなケースを考える 1サイクル終了した時点では スター節点のところに最強呪文として aaaaaac が求まる しかしながら サイクルを繰り返していくと やがてスター節点のところに aaaaaac より強い呪文として aaaaaab が現れるので 最強呪文は存在しないと判定できる 枝のラベルの文字数は最大で6 倍の差があるので おそらく合計 6サイクルぐらい計算を行えば 最強呪文が存在しない場合には 1サイクル終了時点での最強呪文よりも強いものが現れると思われる ( 本当?) プログラム例 // ACM-ICPC 2010 Japan Online Contest Problem E // http://icpc2010.honiden.nii.ac.jp/domestic-contest/problems#section_e // ファイル名 : pe.c // コンパイル方法 : cc pe.c // 実行方法 :./a.out < E0 > E0.result など // チェック方法 : diff E0.ans E0.result など // // アルゴリズム概略 // 各節点に対して その節点から枝 k 本以内でゴールドに至る最強呪文を // k = 1,..., n-1 の順に求める この操作を1サイクルと名付ける // 最強呪文が存在する場合 それはループを含まないので // スター節点の所には その時点で最強呪文が求まっている // これが最強呪文であるためには ループによりこれより強い最強呪文を // 任意個作りだすことができないことを確認する必要がある // スター節点の所に求まっている最強呪文の長さは高々 6(n-1) であり // より強い最強呪文を作り出すループが存在する場合 そのループに含まれる // 文字列長は最短の場合 1 である 従って 合計で 6 サイクル分 (?) 計算を行えば // 1 サイクル目に求められたスター節点の最強呪文よりも強い呪文が求まるはずである // 既に 1 サイクル目の計算は終わっているので あと 5 サイクル分の計算を行ってみて // より強い呪文が出てくれば 最強呪文は存在しない // 一方 より強い呪文が出てこなければ 1 サイクル目に求まっていたものが // 最強呪文となる #include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX_N 40 // 節点数の最大値 #define MAX_A 400 // 枝数の最大値 #define MAX_LABEL_LEN 6 // 枝のラベルの最大文字列長 int n; // 節点数 2 <= n <= 40 int a; // 枝数 0 <= a <= 400 2

int s; // スター節点 0 <= s < 40 int g; // ゴールド節点 0 <= g < 40 // s!= g struct edge_type int src; // 枝の開始節点 int dst; // 枝の終了節点 char label[max_label_len+1]; ; typedef struct edge_type edge_t; // 枝のラベル struct node_type char *css; // 現時点でこの節点からゴールドに至る最強の呪文 char *new; // より強力な新しい呪文 ; typedef struct node_type node_t; edge_t edge[max_a]; node_t node[max_n]; // 枝の情報を格納する配列 // 節点の情報を格納する配列 // 1 サイクル = 枝を n-1 回たどる void cycle(int c) int i,j,k,flag; for(i=0; i < (n-1)*c; i++) // c サイクル分 枝をたどる flag = 0; for(j=0; j<a; j++) // 各枝に対し以下の操作を行う int sn, dn; char *el, *nl; int len1, len2; sn = edge[j].src; // 枝の始点 dn = edge[j].dst; // 枝の終点 el = edge[j].label; // 枝のラベル nl = NULL; // 終点の節点の暫定最強呪文が求まっていない場合は何もしない if(node[dn].css == NULL) continue; len1 = strlen(el); // 枝のラベルの文字列の長さ len2 = strlen(node[dn].css); // 終点節点の暫定最強呪文の長さ nl = (char *)malloc(len1+len2+1); // 新しい呪文を格納する領域を確保 strcpy(nl, el); // 新しい呪文は 枝のラベル+ strcat(nl,node[dn].css); // 終点節点の暫定最強呪文 if(node[sn].new == NULL) // 始点節点に対し新しい呪文が未登録で if(node[sn].css == NULL) // 始点節点に対し暫定最強呪文が未登録なら node[sn].new = nl; // 今作成した新しい呪文を new に登録し else // 始点節点に対し 新呪文は未登録 暫定最強呪文は登録済み // 新しい呪文が暫定最強呪文よりも強ければ if(strcmp(nl, node[sn].css) < 0) node[sn].new = nl; // それを新呪文として登録し else // 始点節点に対し 新呪文が登録済 3

// 新しい呪文が既登録の新呪文よりも強ければ if(strcmp(nl, node[sn].new) < 0) free(node[sn].new); // 古い新呪文の領域を解放し node[sn].new = nl; // 新たに見つかった呪文を新呪文として登録 if(flag) // より強力な新呪文が見つかっていれば for(j=0; j<n; j++) if(node[j].new) // 新呪文が見つかった各節点に対して if(node[j].css) free(node[j].css); // 暫定最強呪文が登録されていれば // その領域を解放する node[j].css = node[j].new; // 登録されていた新呪文を暫定最強呪文とし node[j].new = NULL; // 新呪文は未登録とする else break; // より強力な新呪文は見つからなかったので終了 void solve() char *save; cycle(1); // サイクルを 1 回まわすと ループ無しの最強呪文があれば見つかる if(node[s].css == NULL) printf("no n"); // 見つかっていなければ最強呪文は存在しない return; // 現時点での暫定最強呪文を記憶する領域を確保し保存しておく save = (char *)malloc(strlen(node[s].css)+1); strcpy(save, node[s].css); cycle(5); // あと 5 サイクルまわす if(strcmp(node[s].css, save) < 0) // ループでより強力な呪文を構成できる場合は printf("no n"); // 最強呪文は存在しない else // より強力な呪文を構成できなかった場合は printf("%s n",save); // 先ほど保存しておいたものが最強呪文である free(save); // 最強呪文を保存していた領域を解放 int main() int i,x,y; char labelstr[max_label_len+1]; // 枝のラベル文字列を読み込むための配列 while(1) scanf("%d %d %d %d", &n, &a, &s, &g); // n, a, s, g を入力 if(n==0 && a==0 && s==0 && g==0) break; // 全て0なら終了 for(i=0; i<n; i++) // 各節点に登録される呪文データを未登録状態に初期化 node[i].css = node[i].new = NULL; for(i=0; i<a; i++) 4

// 各枝の開始点 終了点 ラベルを入力 scanf("%d %d %s", &x, &y, labelstr); edge[i].src = x; edge[i].dst = y; strcpy(edge[i].label, labelstr); // ゴールド節点の最強呪文として空文字列を登録 node[g].css = (char *)malloc(1); *node[g].css = ' 0'; solve(); // 答えを求める for(i=0; i<n; i++) // 各節点に登録した呪文データの格納領域を解放 if(node[i].css) free(node[i].css); if(node[i].new) free(node[i].new); 5