プログラミング基礎 I( 再 )

19
プププププププププ I( プ ) プププ

description

プログラミング基礎 I( 再 ). 山元進. 授業評価アンケート. 初めにアンケートに答え る 時間をとる 自由記入欄にも積極的に書きこまれたし. 先週の課題の解説. 出力を各ケタごとに縦に見ると、 7 周期に同じ数字が繰り返すケタと、 3 周期に同じ数字を繰り返すケタとに分かれる グループ A: 3 周期のケタが 3 つ グループ B: 7 周期のケタが 7 つ 基本的なルールは グループ A の中で巡回置換 グループ B の中で巡回置換 の2つで、これを実装すれば " 良い解答 " になる. 良い解答を実装するのは、若干難しい - PowerPoint PPT Presentation

Transcript of プログラミング基礎 I( 再 )

Page 1: プログラミング基礎 I( 再 )

プログラミング基礎 I( 再 )

山元進

Page 2: プログラミング基礎 I( 再 )

授業評価アンケート 初めにアンケートに答える時間をとる 自由記入欄にも積極的に書きこまれたし

Page 3: プログラミング基礎 I( 再 )

先週の課題の解説 出力を各ケタごとに縦に見ると、 7 周期

に同じ数字が繰り返すケタと、 3 周期に同じ数字を繰り返すケタとに分かれる

グループ A: 3 周期のケタが 3 つ グループ B: 7 周期のケタが 7 つ 基本的なルールは

グループ A の中で巡回置換 グループ B の中で巡回置換

の2つで、これを実装すれば " 良い解答 " になる

Page 4: プログラミング基礎 I( 再 )

良い解答を実装するのは、若干難しい そもそも、画面の出力だけみても巡回置換

とは分からないので、動作をチェックするプログラムを作る必要がある

画面出力だけから判断すると、特定の数字の下に表示される数字は決まっている

それを実装したのが " 普通の解答 "

Page 5: プログラミング基礎 I( 再 )

id=999; の場合の変換規則0123456789 1行目は、繰り返し処理の前に実行した print で印字されたもの8901564237 繰り返し処理 1 回目3789645012 繰り返し処理 2 回目1237456890 繰り返し処理 3 回目9012564378789064512323784569010123564789890164523737894560121237564890 規則の明文化の例 0→89012645378 1→97890456123 2→02378564901 3→10123645789 4→58901456237 5→63789564012 6→41237645890 7→29012456378 8→37890564123 9→723786459010123456789 繰り返し処理 21 回目 ここで元の並びに戻ったので繰り返し終了Finished. 終わったしるしに "Finished." と印字

Page 6: プログラミング基礎 I( 再 )

普通の解答例 (id=999)class Ex01{ public static void permutation(int in[]){

int[] permList = {8,9,0,1,5,6,4,2,3,7};for(int i=0; i<10; i++){

in[i]=permList[in[i]]; // ここがポイント}

} public static boolean samePerm(int[] in1, int[] in2){

if(in1.length != in2.length ) return false;boolean flag=true;for(int i=0; i<in1.length; i++) if(in1[i]!=in2[i]) flag=false;return flag; // 一つでも違う数値があったら false を返す

} public static void main(String[] args){

int[] input1={0,1,2,3,4,5,6,7,8,9};int[] input2={0,1,2,3,4,5,6,7,8,9};int id=999;do{ Perm.permutation(id,input1); permutation(input2); if(!samePerm(input1,input2)){ System.out.println("Differ!"); Perm.print(input1); Perm.print(input2); }}while(!Perm.isIdentity(input1));

}}

Page 7: プログラミング基礎 I( 再 )

良い解答の解答例は示さない

permutation メソッドと Perm.permutation  メソッドが、どの入力に対しても 一致することを示すためには、入力の生成方法を考える必要あり 入力は、長さ 10 の整数配列であればなんで良い

わけではなく、 0~9 の数字を並べて作る順列である

今日は 0~9 の数字を並べて作る順列の生成法を題材にする

Page 8: プログラミング基礎 I( 再 )

今日も課題を解くのがメイン 指示をよく読むこと 後の課題で先週利用した Perm.class を

使うので、今日の課題プログラムを作成するディレクトリにコピーしておく

学籍番号の下 3 ケタを 999 と仮定しているサンプルがあるので、それは自分の学籍番号の下 3 ケタに書きかえる

Page 9: プログラミング基礎 I( 再 )

課題 1 ( 下準備 ) 0~3 の数字を並べて作る順列 ( 先頭の数字が 0

である場合を含める ) を、小さい順に全てあげよ ( 解答の最初の 3 項まで ) 0123, 0132, 0213, …

次ページの Ex02.java をどう書き換えれば上の並びを出力するようになるか、説明せよ Ex02 は、 001, 002, 003, という並びを生成して、

同じ数字が繰り返し出てきたら排除している この方法は、簡単だが桁数を変えるのが面倒 上のケタから順に数字を決めてゆく際、使った数字の

リストを作り、重複を排除すると、もうすこしまし 発想が難しいが、プログラムが短くなる方法もある

Page 10: プログラミング基礎 I( 再 )

0~2 の数字を並べてできる順列を、小さい順に全て表示するプログラム (工夫なし版 )

class Ex02{ public static void main(String[] args){

int[] input=new int[3]; for(int i0=0; i0<3; i0++){input[0]=i0;for(int i1=0; i1<3; i1++){if(i1==i0) continue;input[1]=i1;for(int i2=0; i2<3; i2++){if(i2==i0 || i2==i1) continue;input[2]=i2;Perm.print(input);}}}

}}

Page 11: プログラミング基礎 I( 再 )

課題 2( 出力チェック ) 1) 0~5 の数字を並べ替えてできる順列を全

てあげるプログラムを作成せよ。ただし順列は、長さ 6 の整数配列として表されるものとする。

2) この順列は 6!   = 720 通りある。 1 行に 1 つ順列を表示するとすれば、 720 行になる。人手で出力をチェックするには行数が多いので、 linux のコマンドを利用してチェックする方法を考えよ。 sort, uniq (, diff, wc) を使えばできる

3) 実際に出力をチェックせよ

Page 12: プログラミング基礎 I( 再 )

課題 3( 問題の規模拡大 ) 0~9 の数字を並べ替えてできる順列を全

てあげるプログラムを作成せよ。ただし、順列は長さ 10 の整数配列として表されるものとする。 この課題の出力は 328800 行。人手での

チェックは無理。

Page 13: プログラミング基礎 I( 再 )

課題 4( 本題 ) 1) 課題 3 では、生成した順列を画面 ( 標準出

力 ) に出力した。この課題では、画面に出力するかわりに、次の 2 つメソッドの入力として使え。 このパワーポイントの 6 ページにあげた

permutation メソッドを、自分の id 用に書き換えたもの

先週の Perm.class の Perm.permutation 注意 : メソッドの引数として与えた配列は、上の各

メソッドによって書き換えられてしまう。書き換えは、後の操作に支障をきたす。それを避けるため、各メソッドの入力として2つの新たな配列を作り、値をコピーしてから各メソッドの引数とせよ。

Page 14: プログラミング基礎 I( 再 )

課題 4( 続 ) 2) 1) 2 つのメソッドから戻ってきた後 ( 書

き変わった後の ) の整数配列を比較し、各要素の値が完全に一致する場合が何通りあるか数えるプログラムをつくれ。

Page 15: プログラミング基礎 I( 再 )

以下はヒント

Page 16: プログラミング基礎 I( 再 )

sort は、ある欄の値をキーにして辞書式に並べ替えるコマンド

uniq は、隣り合う行が重複する場合、重複を取り除くコマンド

全ての順列が過不足なく印字されているならば、並べ替えた時に重複する行はないはず

他に有用なコマンド 1 :   wc語数を数えるコマンド。 -l オプションをつけると行の数を数える

他に有用なコマンド 2 :   diff 2 つのファイルの違いを画面に表示する

Page 17: プログラミング基礎 I( 再 )

Ex02.java を書き換えて、0~2 の数字を並べて作った順列のうち、210 という順列が何番目の順列かを表示するプログラムclass Ex03{ public static boolean equiv(int[] in1, int[] in2){ // このメソッドは引数を書き変えない

if(in1.length != in2.length ) return false;boolean flag=true;for(int i=0; i<in1.length; i++) if(in1[i]!=in2[i]) flag=false;return flag;

} public static void main(String[] args){

int[] input=new int[3]; int[] ref={2,1,0}; int count=0; for(int i0=0; i0<3; i0++){

input[0]=i0;for(int i1=0; i1<3; i1++){if(i1==i0) continue;input[1]=i1;for(int i2=0; i2<3; i2++){if(i2==i0 || i2==i1) continue;input[2]=i2;count++;if(equiv(input,ref)){System.out.print(count+"番目の順列が");for(int i=0; i<3; i++) System.out.print(ref[i]);System.out.println("になりました。");}}}

} }}

Page 18: プログラミング基礎 I( 再 )

整数配列のコピーint[] copy1 = input.clone();

copy1 が input のコピー (clone) になる copy1 は input とは独立したメモリを確保

している copy1 の値を書き換えても input への影響

はない int[] alias=input; でも alias が整数配列として扱われるが、データを確保するメモリは input と共有。つまり、 alias[i] を書き換えると、 input[i] も同じ値になる。

Page 19: プログラミング基礎 I( 再 )

今回の課題では、int[] copy1 = input.clone();int[] copy2 = input.clone();Perm.permutation(id,copy1);permutation(copy2);if(equiv(copy1,copy2)){

….}

といった使い方を想定している。