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

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

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

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

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

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

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

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

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

kiso2-09.key

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

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

< F2D837C E95CF CF68A4A94C5816A2E6A>

Taro-数値計算の基礎Ⅱ(公開版)

C言語によるアルゴリズムとデータ構造

C のコード例 (Z80 と同機能 ) int main(void) { int i,sum=0; for (i=1; i<=10; i++) sum=sum + i; printf ("sum=%d n",sum); 2

Microsoft PowerPoint - C言語の復習(配布用).ppt [互換モード]

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

PowerPoint Presentation

memo

Taro-ファイル処理(公開版).jtd

Taro-ビット処理(公開版).jtd

Microsoft Word - no15.docx

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

program7app.ppt

kiso2-06.key

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

kiso2-03.key

[1] #include<stdio.h> main() { printf("hello, world."); return 0; } (G1) int long int float ± ±

関数の呼び出し ( 選択ソート ) 選択ソートのプログラム (findminvalue, findandreplace ができているとする ) #include <stdiu.h> #define InFile "data.txt" #define OutFile "surted.txt" #def

プログラミング基礎

Microsoft PowerPoint - kougi10.ppt

関数の呼び出し ( 選択ソート ) 選択ソートのプログラム (findminvalue, findandreplace ができているとする ) #include <stdio.h> #define InFile "data.txt" #define OutFile "sorted.txt" #def

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)* (

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

演習課題No12

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

<4D F736F F D20438CBE8CEA8D758DC03389F0939A82C282AB2E646F63>

PowerPoint プレゼンテーション

PowerPoint プレゼンテーション

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

memo

1 return main() { main main C 1 戻り値の型 関数名 引数 関数ブロックをあらわす中括弧 main() 関数の定義 int main(void){ printf("hello World!!\n"); return 0; 戻り値 1: main() 2.2 C main

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

gengo1-8

printf("5つの整数を入力して下さい \n"); /* データ入力 */ for( /*** 02 ***/ ){ printf("%dつ目の入力 :",i+1); scanf("%d", /*** 03 ***/ ); sum=dat[0]; /* 合計値の初期設定 */ n_max= 0

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

I ASCII ( ) NUL 16 DLE SP P p 1 SOH 17 DC1! 1 A Q a q STX 2 18 DC2 " 2 B R b

Prog1_10th

I. Backus-Naur BNF S + S S * S S x S +, *, x BNF S (parse tree) : * x + x x S * S x + S S S x x (1) * x x * x (2) * + x x x (3) + x * x + x x (4) * *

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

(search: ) [1] ( ) 2 (linear search) (sequential search) 1

PowerPoint プレゼンテーション

PowerPoint プレゼンテーション

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

PowerPoint プレゼンテーション

Microsoft Word - 13

Microsoft PowerPoint - lec10.ppt

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

Microsoft PowerPoint - 11.pptx

:30 12:00 I. I VI II. III. IV. a d V. VI

Microsoft PowerPoint - 4.pptx

Microsoft PowerPoint - lec4.ppt

第2回

memo

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

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

PG13-6S

問題 01 以下は コンソールより年齢を入力させ その年齢にあった料金を表示するプログラムである 年齢ごとの金額は以下の通りである 年齢の範囲金額 0 歳以上 6 歳以下 120 円 7 歳以上 65 歳未満 200 円 65 歳以上無料 package j1.exam02; import java

演算増幅器

PowerPoint プレゼンテーション

Microsoft Word - no11.docx

memo

gengo1-12

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

Microsoft PowerPoint - C4(反復for).ppt

II ( ) prog8-1.c s1542h017%./prog8-1 1 => 35 Hiroshi 2 => 23 Koji 3 => 67 Satoshi 4 => 87 Junko 5 => 64 Ichiro 6 => 89 Mari 7 => 73 D

2006年10月5日(木)実施

Microsoft Word - no103.docx

cp-7. 配列

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

情報処理Ⅰ

Microsoft PowerPoint - algo ppt [互換モード]

スライド 1

Microsoft PowerPoint - 5Chap15.ppt

Microsoft PowerPoint - ca ppt [互換モード]

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

講習No.9

memo

gengo1-11

今回のプログラミングの課題 ( 前回の課題で取り上げた )data.txt の要素をソートして sorted.txt というファイルに書出す ソート (sort) とは : 数の場合 小さいものから大きなもの ( 昇順 ) もしくは 大きなものから小さなもの ( 降順 ) になるよう 並び替えること

:30 12:00 I. I VI II. III. IV. a d V. VI

tuat1.dvi

/* do-while */ #include <stdio.h> #include <math.h> int main(void) double val1, val2, arith_mean, geo_mean; printf( \n ); do printf( ); scanf( %lf, &v

gengo1-12

人工知能入門

PowerPoint プレゼンテーション

memo

Microsoft PowerPoint - 計算機言語 第7回.ppt

‚æ2›ñ C„¾„ê‡Ìš|

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

Transcription:

0. 目次 6. 2 項係数 7. 二分探索 8. 最大値探索 9. 集合 {1,2,,n} 上の部分集合生成 - 1 -

6. 2 項係数 再帰的定義 2 項係数 c(n,r) は つぎのように 定義される c(n,r) = c(n-1,r) + c(n-1,r-1) (n 2,1 r n-1) = 1 (n 0, r=0 ) = 1 (n 1, r=n ) c(n,r) 0 1 2 3 4 5 0 1 1 1 1 2 1 2 1 3 1 3 3 1 4 1 4 6 4 1 5 1 5 10 10 5 1 関数 c(n,r) は 定義通りに書ける プログラム (rf611.c) 1 /* << rf611.c >> */ 2 #include <stdio.h> 3 int c(int n, int r); 4 5 int main() { 6 int n,r; 7 8 while( 1 ) { 9 /* 正整数 n,r の読み込み */ 10 scanf("%d%d",&n,&r); 11 if( (n < 0) (r < 0) (n < r) ) { break; }; 12 13 printf("c(%d,%d) = %d \n",n,r, c(n,r)); 14 } 15 } 16 17 /* 2 項係数の計算 */ 18 int c(int n, int r) { 19 if( (r==0) (n==r) ) { 20 return 1; 21 } else { 22 return c(n-1,r) + c(n-1,r-1); 23 } 24 } - 2 -

実行結果 % cc rf611.c %./a.out 3 2 c(3,2) = 3 10 5 c(10,5) = 252-1 -1 実行時間 % cc rf611.c %./a.out 28 14-1 -1 c(28,14)=40116600 0.411u 0.000s 0:07.32 5.6% 0+0k 0+0io 0pf+0w %./a.out 30 15-1 -1 c(30,15)=155117520 1.582u 0.001s 0:08.53 18.5% 0+0k 0+0io 0pf+0w プログラム (rf611.c) において n,r が与えられたとき 関数 c(n,r) が呼び出される回数 n r 呼び出される回数 4 1 7 4 2 11 4 3 7 4 4 1 関数 c(n,r) の計算過程 n=5,r=2 の場合 c(5,2) c(4,2) c(4,1) c(3,2) c(3,1) c(3,1) c(3,0) c(2,2) c(2,1) c(2,1) c(2,0) c(2,1) c(2,0) c(1,1) c(1,0) c(1,1) c(1,0) c(1,1) c(1,0) ( 注意 ) 同じ計算を繰り返すので大きな n,r に対して効率が悪くなる - 3 -

7. 二分探索 データが配列 d に昇順に並べられているとき行われる二分探索を再帰的に定義する 探索データを x とする 再帰的定義 search(d[i],,d[j],x) = "not found" (i>j) = "found" (i j, x=d[(i+j)/2]) = search(d[i],,d[(i+j)/2-1],x) (i j, x<d[(i+j)/2]) = search(d[(i+j)/2+1],,d[j],x) (i j, x>d[(i+j)/2]) 二分探索関数 search(i,j) のプログラムは次のように書ける プログラム (rf711.c) 1 /* << rf711.c >> */ 2 #include <stdio.h> 3 #include <stdlib.h> 4 #define N 9999 /* データの個数の最大値 */ 5 int d[n+1], /* データを格納する配列 */ 6 x; /* 探索データ */ 7 void search(int i, int j); 8 9 int main() { 10 int i, 11 n; /* データの個数 */ 12 13 /* データの個数 nとデータの読み込み */ 14 scanf("%d",&n); 15 if( (n <= 0) (n > N) ) { exit(0); } 16 for( i=1; i<=n; i++ ) { d[i] = i*10; } 17 18 /* 二分探索 */ 19 while( 1 ) { 20 /* 探索データ xの読み込み */ 21 scanf("%d",&x); 22 if( x <= 0 ) { break; } 23 search(1,n); 24 } 25 } 26 27 /* 再帰的定義 */ 28 void search(int i, int j) { 29 int m; 30 if( i > j ) { 31 printf("%dはみつかりません \n",x); return; - 4 -

32 } 33 m = (i+j)/2; 34 if( x == d[m] ) { 35 printf("%dが見つかりました \n",x); return; 36 } 37 if( x <= d[m] ) { 38 search(i,m-1); 39 } else { 40 search(m+1,j); 41 } 42 return; 43 } 実行結果 % cc rf711.c %./a.out 10 30 30 が見つかりました 55 55 は見つかりません 0 プログラム (rf711.c) において 100 個のデータ 10,20,,1000 が与えられたとき 探索データ x を探索するため関数 search(i,j) が呼び出される回数 x 呼び出される回数 100 6 500 1 123 7 345 7-5 -

プログラム (rf711.c) の動作 10 個のデータ 10,20,,100 x=30 の場合 search(1,10) 1 2 3 4 5 6 7 8 9 10 10 20 30 40 50 60 70 80 90 100 m=(1+10)/2=5 search(1,4) 1 2 3 4 10 20 30 40 m=(1+4)/2=2 search(3,4) 3 4 30 40 m=(3+4)/2=3 見つかった 3 4 30 40 x=55 の場合 search(1,10) 1 2 3 4 5 6 7 8 9 10 10 20 30 40 50 60 70 80 90 100 m=(1+10)/2=5 search(6,10) 6 7 8 9 10 60 70 80 90 100 m=(6+10)/2=8 search(6,7) 6 7 60 70 m=(6+7)/2=6 search(6,5) 1 2 3 4 5 6 7 8 9 10 見つからない 10 20 30 40 50 60 70 80 90 100-6 -

8. 最大値探索 n 個のデータ中 最大のものを見つける方法を再帰的に考える 再帰的定義 1 max(d[1],,d[n]) = max(max(d[1],,d[n-1]),d[n]) (n>1) = d[1] (n=1) n=5の場合 max(d[1],d[2],d[3],d[4],d[5]) max(d[1],d[2],d[3],d[4]) d[5] max(d[1],d[2],d[3]) d[4] max(d[1],d[2]) d[3] max(d[1]) d[2] - 7 -

最大値関数 max(i): d[1] から d[i] までの中から最大の要素を返す 最大値を求めるプログラムは次のように書ける プログラム (rf811.c) 1 /* << rf811.c >> */ 2 #include <stdio.h> 3 #include <stdlib.h> 4 #define N 9999 /* データの個数の最大値 */ 5 int d[n+1], /* データを格納する配列 */ 6 int max(int i); 7 8 int main() { 9 int i, 10 n; /* データの個数 */ 11 12 /* データの個数とデータを入力 */ 13 scanf("%d",&n); 14 if( (n <= 0) (n > N) ) { exit(0); } 15 for( i=1; i<=n; i++ ) { scanf("%d",&d[i]); } 16 17 /* データの出力 */ 18 for( i=1; i<=n; i++ ) { 19 printf("%5d ",d[i]); 20 if( i%10==0 ) { printf("\n"); } 21 } 22 printf("\n 最大値 : %d \n",max(n)); 23 } 24 25 /* d[1] から d[i] までの中から最大の要素を返す */ 26 int max(int i) { 27 int z,z1,z2; 28 if( i == 1 ) { 29 z = d[1]; 30 } else { 31 z1 = max(i-1); 32 z2 = d[i]; 33 if( z1 > z2 ) { 34 z = z1; 35 } else { 36 z = z2; 37 } 38 } 39 return z; 40 } - 8 -

実行結果 1 % cc rf811.c 2 %./a.out 3 9 4 44 55 88 33 99 22 11 66 77 5 44 55 88 33 99 22 11 66 77 6 最大値 : 99 再帰的定義 2 max(d[i],,d[j]) = max(max(d[i],,d[k]),max(d[k+1],,d[j])) (i<j, k は適当な値 i k<j) = d[i] (i=j) n=5,k=(i+j)/2 の場合 max(d[1],d[2],d[3],d[4],d[5]) k=(1+5)/2=3 max(d[1],d[2],d[3]) k=(1+3)/2=2 max(d[4],d[5]) k=(4+5)/2=4 max(d[1],d[2]) max(d[3]) max(d[4]) max(d[5]) k=(1+2)/2 max(d[1]) max(d[2]) 最大値関数 max(i,j): d[i] から d[j] までの中から最大の要素を返す 最大値を求めるプログラムは次のように書ける プログラム (rf821.c) 1 /* << rf821.c >> */ 2 #include <stdio.h> 3 #include <stdlib.h> 4 #define N 9999 /* データの個数の最大値 */ 5 int d[n+1], /* データを格納する配列 */ 6 int max(int i, int j); 7 8 int main() { 9 int i, 10 n; /* データの個数 */ 11-9 -

12 /* データの個数 nとデータを入力 */ 13 scanf("%d",&n); 14 if( (n <= 0) (n > N) ) { exit(0); } 15 for( i=1; i<=n; i++ ) { scanf("%d",&d[i]); } 16 17 /* データの出力 */ 18 for( i=1; i<=n; i++ ) { 19 printf("%5d ",d[i]); if( i%10==0 ) { printf("\n"); } 20 } 21 printf("\n"); 22 printf(" 最大値 : %d \n",max(1,n)); 23 } 24 25 /* d[i] から d[j] までの中から最大の要素を返す */ 26 int max(int i, int j) { 27 int k,z,z1,z2; 28 if( i == j ) { 29 z = d[i]; 30 } else { 31 k = (i+j)/2; 32 z1 = max(i,k); 33 z2 = max(k+1,j); 34 if( z1 > z2 ) { 35 z = z1; 36 } else { 37 z = z2; 38 } 39 } 40 return z; 41 } 実行結果 1 % cc rf821.c 2 %./a.out 3 9 4 44 55 88 33 99 22 11 66 77 5 44 55 88 33 99 22 11 66 77 6 最大値 : 99-10 -

9. 集合 {1,2,,n} 上の部分集合生成 集合 {1,2,,n} 上の部分集合を示す n 部分集合 B(n) 1 {},{1} 2 {},{1},{2},{1,2} 3 {},{1},{2},{3},{1,2},{1,3},{2,3},{1,2,3} 4 {},{1},{2},{3},{4},{1,2},{1,3},{1,4},{2,3},{2,4} {3,4},{1,2,3},{1,2,4},{1,3,4},{2,3,4},{1,2,3,4} 集合 {1,2,,n} 上の部分集合の個数 集合 {1,2,,n} 上の部分集合の個数 f(n) とおくと 要素 1 を含む部分集合と要素 1 を含まない部分集合に分類できる 前者は f(n-1) 個の部分集合 後者も f(n-1) 個の部分集合を含む このことから 漸化式 f(n) = f(n-1) + f(n-1) (n 2), f(1)=2 を得る この漸化式を解くと となる 表現法 1 n f(n) = 2 (n 1) 記号 0,1 からなる長さ n の記号列 a(1)a(2) a(n) で部分集合を表す ただし a(i)=0 で 要素 i が部分集合に含まれない a(i)=1 で 要素 i が部分集合に含まれることに対応させる 記号 0,1 からなる長さ n の記号列 a(1)a(2) a(n) の集合を A(n) とする n 部分集合 A(n) 1 0,1 2 00,01,10,11 3 000,001,010,011,100,101,110,111 4 0000,0001,0010,0011,0100,0101,0110,0111, 1000,1001,1010,1011,1100,1101,1110,1111-11 -

いくつかの文字列の並び S={s1,s 2,,sp}, T={t1,t 2,,t q} が与えられたとき as, S+T を次のように定義する as = {as1,as 2,,as p} S+T = {s1,s 2,,s p,t 1,t 2,,tq} このとき A(n) は 次のようにも書ける A(1) = {0,1} A(n) = 0A(n-1) + 1A(n-1) (n 2) A(2) = 0A(1) + 1A(1) = 0{0,1} + 1{0,1} = {00,01,10,11} A(3) = 0A(2) + 1A(2) = 0{00,01,10,11} + 1{00,01,10,11} = {000,001,010,011,100,101,110,111} A(4) = 0A(3) + 1A(3) = 0{000,001,010,011,100,101,110,111} + 1{000,001,010,011,100,101,110,111} = {0000,0001,0010,0011,0100,0101,0110,0111, 1000,1001,1010,1011,1100,1101,1110,1111} 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 1 0 0 0 1 1 0 0 1 0 0 0 1 0 A(1) 1 1 0 1 1 0 0 1 1 1 0 0 0 1 0 0 A(2)=0A(1)+1A(1) 1 0 1 0 1 0 1 1 1 0 0 1 1 0 1 1 1 0 1 1 1 1 0 0 0 A(3)=0A(2)+1A(2) 1 0 0 1 1 0 1 0 1 0 1 1 1 1 0 0 1 1 0 1 1 1 1 0 1 1 1 1 A(4)=0A(3)+1A(3) - 12 -

A(1) = {0,1} A(n) = 0A(n-1) + 1A(n-1) (n 2) 上記の表現に基づくプログラムは次のように書ける プログラム (rf911.c) 1 /* << rf911.c >> */ 2 #include <stdio.h> 3 #define N 9 /* 要素数の最大値 */ 4 int a[n+1], /* 部分集合を表現する配列 */ 5 count, /* 部分集合の個数 */ 6 n; /* 集合の要素数 */ 7 void sub(int k); 8 9 int main() { 10 while( 1 ) { 11 /* 要素数 nの読み込み */ 12 scanf("%d",&n); 13 if( (n <= 0) (n > N) ) { break; } 14 15 /* 初期設定 */ 16 count = 0; 17 18 /* 部分集合の生成 */ 19 sub(1); 20 printf("n=%d count=%d\n",n,count); 21 } 22 } 23 24 /* k 番目から n 番目までの要素の部分集合を生成する */ 25 void sub(int k) { 26 int i; 27 if( k > n ) { 28 count++; printf("%d: ",count); 29 for( i=1; i<k; i++ ) { 30 printf("%d ",a[i]); 31 } 32 printf("\n"); 33 } else { 34 /* k 番目の要素を含まない部分集合を生成 */ 35 a[k] = 0; sub(k+1); 36 /* k 番目の要素を含む部分集合を生成 */ 37 a[k] = 1; sub(k+1); 38 } 39 } - 13 -

実行結果 % cc rf911.c %./a.out 3 1: 0 0 0 2: 0 0 1 3: 0 1 0 4: 0 1 1 5: 1 0 0 6: 1 0 1 7: 1 1 0 8: 1 1 1 n=3 count=8 0 プログラム (rf1011.c) において n が与えられたとき 関数 sub が呼び出される回数 木の表現 1 n 呼び出される回数 3 15 4 31 5 63 6 127 部分集合 A(n) を木で表現する a(i)=0 は 深さ i で要素 i が集合に含まれないことを意味し a(i)=1 は 深さ i で要素 i が集合に含まれることを意味する 記号 0 の子を 0,1 と並べ 記号 1 の子も 0,1 と並べる 要素 1 0 1 要素 2 0 1 0 1 要素 3 0 1 0 1 0 1 0 1 要素 40 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 根 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1-14 -