創造工学演習・予備実験・パズル問題
プログラミングコンテストの競技部門では、パズルのような組み合わせ問題が 出題されることが多い。また、課題部門や自由部門であっても、複数の条件の組み合わせの中から最良のものを選ぶといった処理も求められる。そこで、この予備実験では、きわめて単純なパズル問題(組み合わせ問題) のプログラムについて扱う。
組み合わせ問題の基礎
簡単な問題として「100未満の整数の値を3つ選び、その値を辺の長さとした場合、 直角三角形となるものをすべて表示する。」について考える。
一番簡単な方法は、以下となるであろう。
#include <stdio.h> #include <math.h> #include <time.h> // 整数比の直角三角形の一覧を求める。 void integer_triangle( int n ) { for( int a = 1 ; a < n ; a++ ) { for( int b = 1 ; b < n ; b++ ) { // 一番ダサい方法 for( int c = 1 ; c < n ; c++ ) { if ( a*a + b*b == c*c ) { printf( "%d %d %d\n" , a , b , c ) ; } } } } } int main() { integer_triangle( 100 ) ; return 0 ; }
しかしこのプログラムの欠点としては、100×100×100回のループで無駄な処理が多い。
ループ回数を減らすだけなら、最も内側の処理を、計算で整数値か確認すればいい。
void integer_triangle( int n ) { for( int a = 1 ; a < n ; a++ ) { for( int b = 1 ; b < n ; b++ ) { // ココも改良できるよね? int d = a*a + b*b ; int c = (int)sqrt( d ) ; // 斜辺Cの整数値を求め、改めて確認する。 if ( c*c == d ) { printf( "%d %d %d\n" , a , b , c ) ; } } } }
(1) 計算誤差の問題を考えてみよう。
たとえば、3:4:5の直角三角形で、3*3+4*4 = 25 だが、sqrt(25)は実数で計算するから、 計算誤差で4.99999で求まったらどうなるだろうか?
1~100までの数値で、”int c = sqrt( (double)(i*i) ) ;” を計算してみて、 異なる値が求まることはあるか? 多少の計算誤差があっても正しく処理が行われるにはどうすればいいか、考えてみよう。
(2) 無駄な答えについて考えてみよう。
このプログラムの答えでは、簡単な整数比の答えの「整数倍の答え」も表示されてしまう。 たとえば、(3:4:5)の答えのほかに、(6:8:10)も表示される。 こういった答えを表示しないようにするにはどうすればよいか?
また、この2つのプログラムの処理時間を実際に比べてみる。
#include <stdio.h> #include <time.h> int main() { time_t start , end ; // time() 関数は、秒数しか求まらないので、 // あえて処理を1000回繰り返し、数秒かかる処理にする。 start = time( NULL ) ; for( int i = 0 ; i < 1000 ; i++ ) { // ただし、関数内のprintfをコメントアウトしておくこと integer_triangle( 100 ) ; } end = time( NULL ) ; printf( "%lf\n" , difftime( end , start ) ) ; return 0 ; }
再帰プログラミング
組み合わせ問題では、forループの多重の入れ子で問題を解けない場合が多い。 (書けないことはないけど無駄なループで処理が遅くなるか、入れ子段数が可変にできない。)
こういった場合には、再帰プログラミングがよく利用される。 もっとも簡単な再帰の例として、階乗のプログラムを考える。 通常であれば、以下のような for ループで記述することになるだろう。
// 階乗の計算 int fact( int x ) { // ループ int f = 1 ; for( int i = 2 ; i <= x ; i++ ) f = f * i ; return f ; }
再帰呼び出しでは、関数の処理の中に、自分自身の関数呼び出しが含まれる。 また、無限に自分自身を呼び出したら処理が止まらないので、 問題を一つ小さくして、これ以上小さくできないときは処理を止めるように記述する。
int fact( int x ) { // 再帰呼び出し if ( x <= 1 ) return 1 ; else return x * fact( x - 1 ) ; }
ここ以降は、指定長さを指定辺の組み合わせで作る課題と、後に述べるFlood-fill 課題の選択とする。
指定長を指定辺の組み合わせで作る(テーマ1)
再帰を使った簡単なパズル問題として、以下のプログラムを作成したい。
配列の中に、複数の辺の長さが入っている。これを組み合わせて指定した長さを作れ。 使用する辺はできるだけ少ない方がよい。
int a[] = { 4 , 5 , 2 , 1 , 3 , 7 } ;
(例) 辺の長さ10を作るには、(5,4,1)とか(7,3)などが考えられる。
これは、ナップサック問題の基本問題で、容量の決まったナップサックに最大量入れる組合せを求めるのと同じである。
このプログラムを解くには…
10 を [4,5,2,1,3,7] で作るには... (0) 6=10-4 を [4|5,2,1,3,7]で作る。 (1) 5=10-5 を [5|4,2,1,3,7]で作る。 (2) 8=10-2 を [2|5,4,1,3,7]で作る。 (3) 9=10-1 を [1|5,2,4,3,7]で作る。 (4) 7=10-3 を [3|5,2,1,4,7]で作る。 (5) 3=10-7 を [7|5,2,1,3,4]で作る。
そこで、ここまでの考えを、以下のようなプログラムで記述してみる。
# まだ再起呼び出しにはしていない。
// 指定されたデータを入れ替える。 void swap( int*a , int*b ) { int x = *a ; *a = *b ; *b = x ; } void check( int array[] , int size , int len , int n ) { // array[] 配列 // size 配列サイズ // len 作りたい長さ // n 使った個数 for( int i = n ; i < size ; i++ ) { // i番目を先頭に... swap( &array[ n ] , &array[ i ] ) ; printf( "check( array , %d , %d , %d )\n" , size , len - array[ n ] , n+1 ) ; // 最初のswapでの変更を元に戻す。 swap( &array[ i ] , &array[ n ] ) ; } } int main() { int a[] = { 4 , 5 , 2 , 1 , 3 , 7 } ; check( a , 6 , 10 , 0 ) ; }
(1) これを再帰呼び出しにしてみよう。どう書けばいい?
void check( int array[] , int size , int len , int n )
{
// array[] 配列
// size 配列サイズ
// len 作りたい長さ
// n 使った個数
if ( len < 0 ) {
// 指定した丁度の長さを作れなかった。
;
} else if ( len == 0 ) {
// 指定した長さを作れたので答えを表示。
for( int i = 0 ; i < n ; i++ ) {
printf( "%d " , array[ i ] ) ;
}
printf( "\n" ) ;
} else {
// 問題を一つ小さくして再帰。
for( int i = n ; i < size ; i++ ) {
swap( &array[ n ] , &array[ i ] ) ;
printf( "check( array , %d , %d , %d )\n" ,
size , len - array[ n ] , n+1 ) ;
check( array , size , len - array[ n ] , n + 1 ) ;
swap( &array[ i ] , &array[ n ] ) ;
}
}
}
(2) 少ない組み合わせの方がポイントが高い場合には、プログラムをどう変更する?
(3) 答えが1つだけで良い場合は、プログラムをどう変更する?
(4) このプログラムでは、冗長な答えがあるか?ないか?検討せよ。
(5) 前設問の整数比直角三角形のプログラムで、冗長な答えを削除するプログラムを作成せよ。
# レポートでは、(2),(3),(4)を検討した結果を実験すること。(5)までチャレンジした人は(2),(3),(4)の説明は簡単に記載するだけで良い。
Flood fill アルゴリズム
前の問題は、今年度のプログラミングコンテストの課題のパズルとは、方向性が違うので、今年度のプロコンの競技部門に近いパズルネタで演習。(Wikipedia Flood-fill参照)
以下の image のような2次元配列が与えられたら、指定座標(x,y)を中心に周囲を塗りつぶす処理を作成せよ。
include <stdio.h> // *は壁 SPCは白 この領域の指定位置を#で塗りつぶす。 char image1[10][10] = { // (4,4)始点で塗りつぶし後 "*********" , // ********* "* * *" , // * *###* "* * *" , // * *###* "* * *" , // * *####* "*** ***" , // ***###*** "* * *" , // *####* * "* * *" , // *###* * "* * *" , // *###* * "*********" , // ********* } ; char image2[10][10] = { // 応用問題用の画像例 "*********" , // * のような隙間は通り抜けられる "* * *" , // * ようにするにはどうすればいい? "* ** *" , // ** "* ** *" , // ** これは通り抜けられない "*** ***" , // ** "* * *" , "* * *" , "* * *" , "*********" , } ; // 盤面を表示 void print_image( char image[10][10] ) { for( int y = 0 ; y < 9 ; y++ ) { for( int x = 0 ; x < 9 ; x++ ) { printf( "%c" , image[y][x] ) ; } printf( "\n" ) ; } } // 再帰呼び出しを使った flud_fill アルゴリズム void flood_fill( char image[10][10] , int x , int y , char fill ) { // image: 塗りつぶす画像 // x,y: 塗りつぶす場所 // fill: 書き込む文字 // 指定座標が空白なら if ( image[y][x] == ' ' ) { // その座標を埋める image[y][x] = fill ; ////////////////////////////////////// // ここに周囲をflud_fillする処理を書く // ////////////////////////////////////// } } int main() { print_image( image1 ) ; flood_fill( image1 , 4 , 4 , '#' ) ; print_image( image1 ) ; return 0 ; }
応用問題
Wikipediaのflood-fill のプログラムの説明のアルゴリズムでは、左図黒のような斜めに並んだブロックは、境界として通り抜けられないようにつくられている。
そこで、斜めに並んだブロックは通り抜けられるルールとした場合のプログラムを記述せよ。
レポート提出
レポートでは、指定長を辺の組み合わせで作るテーマか、Flood-fill のテーマのいずれかにて、以下の内容をまとめてレポートとして提出すること。
-
- レポートの説明(自分の選んだテーマと自分なりの説明)
- プログラムリスト
- 動作確認の結果
サーヴェイとは(FD研修会)
発想法の指導に関するFD研修会
サーヴェイ
はじめに
- 論理立てて思考する起点を見出すのがサーヴェイ
- デザインの作ろうとする物事の仕組みや考えを論理立てて説明出来るための要
- 自身が納得できて、説得するためではなく説明の基礎
アイデア・イメージメモ
- 考えの写真・図・イラスト
- コメント1(思いつき、気付き、疑問、不、好感、利点など)
- コメント2(提案、発展、課題など)
- その他
Surveyとは、
- SurveyとResearchの違い
- Research…研究・調査
- 研究する、調査する
- Survey …調査、探査、測量、実地踏査
- 見渡す、概観する
- field work …実地研究、野外調査、実地調査、現地調査、巡見
- Research…研究・調査
- 探検・発見
ResearchとSurveyの相違
- リサーチ
- 準備して調べること
- 縛りが強い、決め事がある
- 客観的
- 設定
- 定数的
- やや論理的
- ロジカル、裏付け的
- 準備して調べること
- サーヴェイ
- 特に準備なく体感すること
- 縛りがゆるやか、決め事はない
- 主観的
- 想定
- 定性的
- 感覚的
- エモーショナル、曖昧さがあっていい
- 特に準備なく体感すること
Surveyでの留意点
- サーヴェイは、情報・データを得る方法の1つ
- 問題を発見する方法
- ポイント
- 先入観を持たずに概観(常識や固定観念をはずす)
- 自分の経験や知識を一度仕舞い込む
- 常識や規則、良識に囚われていないかと自分に問う
- 自分の五感+αに素直(感じや思いを表出する)
- 感じるがまま、思うがままを表現
- 幼少時の感覚を思い起こす
- 純真な子供に成り代わって素直に対象と接する
- 気付き、思いつきをメモ
- 記号化 – 話し言葉、書き言葉、絵、写真、図など「うつし」
- 取捨選択をしない
- あまり深く考えない
- 結論や解を求めない
- 評価しない
- 記号化 – 話し言葉、書き言葉、絵、写真、図など「うつし」
- 先入観を持たずに概観(常識や固定観念をはずす)
- 気になることがない…という場合には
- アイデアイメージを書けない理由
- こんなことはできない、不可能だから言わない、提案しても採用されない…
- 曼荼羅法→根拠理由を考えて再度行う
- なぜ書けないを曼荼羅法で気づかせる
- なぜ、どうしてと問わない。関わり、関係を考えない
- アイデアイメージを書けない理由
Surveyからメモ作成での姿勢と方向
- 対象の概観(観察)
- 時間を区切る
- (5) / 15 / (30) / 45 / 90 分
- 5分でまとめる(連想法を5分で…)
- 30分以上同じことをさせない
- 自他の評価を考えない・行わない
- 対象の良い点も悪い点も見つける
- 曼荼羅法、
- 3×3の表
- 真ん中にテーマと気付き
- その周り8コマにアイデア(上下左右にプラスマイナス)
- プラスマイナスカード法、
- Brain Writing法、
- Brain Storming法(希望点列挙法,欠点列挙法)
- 曼荼羅法、
- 素直に問う
- 気になることを「何だろう」「どうしてかな」と自問する
- 話す・見せる
- ▶︎サーヴェイによるデータ・資料作成のプロセスとなる
サーヴェイの位置付け・必要性・実施の意味
- サーヴェイ
- 問題の発見 … 問う「なぜ?」「どうして?」と疑問に思うこと
- 問題の探索 … さぐる、さがす
- 問題の把握 … 全貌と細部(ディテール、詳細) → 現状把握・確認
- 「発想のネタ」、「創造のいとぐち」を見出すためのプロセスの最初の行為であり思考
- サーヴェイと問題
- 発見、把握、探索
サーヴェイの発散・収束の思考
- イメージからアイデアに
- 探索→発見→把握→探索…のスパイラルアップ
- 感覚的から論理的に
- 関係や関わりも探り考える(空間・場・時間・機会・遊・休・知・美・感・交・操・演)
発想を出す時のテクニック
- Surveyする時の写真は、モノクロの方がいい
- 余計な情報が先入観になってしまう
- 写真にマーカーを入れる
- マーク付けした所をもとに議論
創造工学演習発表会
創造工学演習
- 07/30 (不明飛行物捕手) UFOキャッチャーのシミュレータをUnityで作成。UFOキャッチャーの有名な技をいくつか実践できることを目指した。(UFOキャッチャーに3000円ツッコム想定でレベル変化。俺は500円以上ツッコンだことない) #創造工学演習
- 07/30 (不明飛行物捕手) UFOキャッチャーのシミュレータ #創造工学演習 https://twitter.com/TohruSaitoh/status/1…
- 07/30 (Typing. edu) タイピング練習とプログラミングのためのタイピング? もう少しプログラミングの言語をイメージした練習ワードをでるようにして欲しかったり。でもこれは情報系ジジイ教員の感想ね。 #創造工学演習
- 07/30 (sin Go!!) 信号はsignalとかsignだしsign(しん)go(ごー)じゃね? #創造工学演習
- 07/30 (sin Go!!) 運転支援で信号の変化を予測できないか…。信号情報はVICSから取得したいが、そのハードは開発困難で想定データを受信できたとしてシステム構築。データが公開されている地域も限定的なのでデータフォーマットなども想定で作らざるおえなかったみたい。 #創造工学演習
- 07/30 (sin Go!!) #創造工学演習 https://twitter.com/TohruSaitoh/status/1…
- 07/30 (ideal idea) アイデア発想の支援するために、曼荼羅法などの機能を実装。関連ワードの検索で支援。検索結果の内容を評価ができれば高評価だけど…。関連ワード検索などは動くけど複数人の利用を想定したセッション管理は未実装かな。 #創造工学演習
- 07/30 (ideal idea) #創造工学演習 https://twitter.com/TohruSaitoh/status/1…
- 07/30 (UnEI-C) 学祭の運営の支援システム構築。発表がソフトコンペのような丁寧なアイデア提案型で始まったけど、全般にわたるいい説明ですな。1人説明だけどな。支援のためのページを簡単生成できるような自動化について議論が欲しかった。 #創造工学演習
- 07/30 (UnEI-C) #創造工学演習 https://twitter.com/TohruSaitoh/status/1…
- 07/30 質問者から「実際にお客さんにサービス提供したとして幾ら?」との質問。シビアな質問だけど、先日訪問した情報・経営システム工学課程なら、定番の質問だろうな。ま、本科4年では意識を持てるだけで充分。 #創造工学演習
- 07/30 →ALL 自分たちで作ったもの写メってTweetしたかぁ?? #創造工学演習
- 07/30 (忘れ物防止) RFIDで忘れ物防止システムの構築。発表は実装重視型かな。個人的には好きだけどね。グループで作るネタをうまく配分してたかな。 #創造工学演習
- 07/30 (忘れ物防止) #創造工学演習 https://twitter.com/TohruSaitoh/status/1…
- 07/30 (ceries) 複数の希望に応じた候補のランキングなどのアルゴリズムの説明が欲しい。Instagram連携にチャレンジしているのは女の子らしくってGoodだけど、そこは未完か…残念。 #創造工学演習
- 07/30 (ceries) 週末デートをどうするか支援するアプリだとぉ〜。非リア充は土日は引きこもりなんだよ。 #創造工学演習
- 07/30 (TCMS) 注文までのインタフェースは基本が完成していた。作るメニューの画面を写真とテキストを与えたら自動生成するなどの対応を期待。発注の流れをメールに割り切ったのは基本機能を完成させる点でアリかな。 #創造工学演習
- 07/30 (競技部門) 敵の行動予測をしたい,先の手をもっと読ませたいとの目標だけど、同じじゃ無いか? 領域ポイントの戦略がこのゲームの面白さなので、フィールドスカスカのターン数のはず。スカスカな状態で終わるターン数でもっと戦略を試してほしい。 #創造工学演習
高専プロコン連携シンポジウム2019
〜セキュリティの観点からプロコンに期待すること〜
高専プロコンの応募に合わせ、以下のような講演会が開催されます。
今年度は、課題部門で「ICT を活用した地域活性化」,自由部門で「クラウドコンピューティング」「オープンデータ」「サイバーセキュリティ」「人工知能」がキーワードに挙げられており、高専生に現場のニーズや動向を学習する機会として、開催されます。
日 時: | 5月20日(月) 16:20〜16:50 Skype for businessを用いた動画配信 |
学内場所: | 電子情報工学科3F 情報処理演習室 |
講 師: | 株式会社日立製作所 セキュリティ事業統括本部サイバーセキュリティ技術本部 セキュリティ人材統括センタセンタ長千葉寛之様 |
講演テーマ: | セキュリティの観点からプロコンに期待すること |
補 足: | 発言・質問は、Twitter(ハッシュタグ #procon30 にて)受付 |
予備実験2 パズル問題
プログラミングコンテストの競技部門では、パズルのような組み合わせ問題が 出題されることが多い。そこで、この予備実験では、きわめて単純なパズル問題(組み合わせ問題) のプログラムについて扱う。
組み合わせ問題の基礎
簡単な問題として、「100未満の整数の値を3つ選び、その値を辺の長さとした場合、 直角三角形となるものをすべて表示する。」について考える。
一番簡単な方法は、以下となるであろう。
#include <stdio.h> #include <math.h> #include <time.h> // 整数比の直角三角形の一覧を求める。 void integer_triangle( int n ) { for( int a = 1 ; a < n ; a++ ) { for( int b = 1 ; b < n ; b++ ) { // 一番ダサい方法 for( int c = 1 ; c < n ; c++ ) { if ( a*a + b*b == c*c ) { printf( "%d %d %d\n" , a , b , c ) ; } } } } } int main() { integer_triangle( 100 ) ; return 0 ; }
しかしこのプログラムの欠点としては、100×100×100回のループで無駄な処理が多い。
ループ回数を減らすだけなら、最も内側の処理を、計算で整数値か確認すればいい。
void integer_triangle( int n ) { for( int a = 1 ; a < n ; a++ ) { for( int b = 1 ; b < n ; b++ ) { // ココも改良できるよね? int d = a*a + b*b ; int c = (int)sqrt( d ) ; // 斜辺Cの整数値を求め、改めて確認する。 if ( c*c == d ) { printf( "%d %d %d\n" , a , b , c ) ; } } } }
(1) 計算誤差の問題を考えてみよう。
たとえば、3:4:5の直角三角形で、3*3+4*4 = 25 だが、sqrt(25)は実数で計算するから、 計算誤差で4.99999で求まったらどうなるだろうか?
1~100までの数値で、”int a = sqrt( (double)(i*i) ) ;” を計算してみて、 異なる値が求まることはあるか? 多少の計算誤差があっても正しく処理が行われるにはどうすればいいか、考えてみよう。
(2) 無駄な答えについて考えてみよう。
このプログラムの答えでは、簡単な整数比の答えの「整数倍の答え」も表示されてしまう。 たとえば、(3:4:5)の答えのほかに、(6:8:10)も表示される。 こういった答えを表示しないようにするにはどうすればよいか?
また、この2つのプログラムの処理時間を実際に比べてみる。
int main() { time_t start , end ; // time() 関数は、秒数しか求まらないので、 // あえて処理を1000回繰り返し、数秒かかる処理にする。 start = time( NULL ) ; for( int i = 0 ; i < 1000 ; i++ ) { // ただし、関数内のprintfをコメントアウトしておくこと integer_triangle( 100 ) ; } end = time( NULL ) ; printf( "%lf\n" , difftime( end , start ) ) ; return 0 ; }
再帰プログラミング
組み合わせ問題では、forループの多重の入れ子で問題を解けない場合が多い。 (書けないことはないけど無駄なループで処理が遅くなるか、入れ子段数が可変にできない。)
こういった場合には、再帰プログラミングがよく利用される。 もっとも簡単な再帰の例として、階乗のプログラムを考える。 通常であれば、以下のような for ループで記述することになるだろう。
// 階乗の計算 int fact( int x ) { // ループ int f = 1 ; for( int i = 2 ; i <= x ; i++ ) f = f * i ; return f ; }
再帰呼び出しでは、関数の処理の中に、自分自身の関数呼び出しが含まれる。 また、無限に自分自身を呼び出したら処理が止まらないので、 問題を一つ小さくして、これ以上小さくできないときは処理を止めるように記述する。
int fact( int x ) { // 再帰呼び出し if ( x <= 1 ) return 1 ; else return x * fact( x - 1 ) ; }
ここ以降は、指定長さを指定辺の組み合わせで作ると、Flood-fill の選択とする。
指定長を指定辺の組み合わせで作る
再帰を使った簡単なパズル問題として、以下のプログラムを作成したい。
配列の中に、複数の辺の長さが入っている。これを組み合わせて指定した長さを作れ。 使用する辺はできるだけ少ない方がよい。
int a[] = { 4 , 5 , 2 , 1 , 3 , 7 } ;
(例) 辺の長さ10を作るには、(5,4,1)とか(7,3)などが考えられる。
これは、ナップサック問題の基本問題で、容量の決まったナップサックに最大量入れる組合せを求めるのと同じである。
このプログラムを解くには…
10 を [4,5,2,1,3,7] で作るには... (0) 6=10-4 を [5,2,1,3,7]で作る。 (1) 5=10-5 を [4,2,1,3,7]で作る。 (2) 8=10-2 を [5,4,1,3,7]で作る。 (3) 9=10-1 を [5,2,4,3,7]で作る。 (4) 7=10-3 を [5,2,1,4,7]で作る。 (5) 3=10-7 を [5,2,1,3,4]で作る。
そこで、ここまでの考えを、以下のようなプログラムで記述してみる。
// 指定されたデータを入れ替える。 void swap( int*a , int*b ) { int x = *a ; *a = *b ; *b = x ; } void check( int array[] , int size , int len , int n ) { // array[] 配列 // size 配列サイズ // len 作りたい長さ // n 使った個数 for( int i = n ; i < size ; i++ ) { // i番目を先頭に... swap( &array[ n ] , &array[ i ] ) ; printf( "check( array , %d , %d , %d )\n" , size , len - array[ n ] , n+1 ) ; // 最初のswapでの変更を元に戻す。 swap( &array[ i ] , &array[ n ] ) ; } } int main() { int a[] = { 4 , 5 , 2 , 1 , 3 , 7 } ; check( a , 6 , 10 , 0 ) ; }
(1) これを再帰呼び出しにしてみよう。どう書けばいい?
void check( int array[] , int size , int len , int n ) { // array[] 配列 // size 配列サイズ // len 作りたい長さ // n 使った個数 if ( len < 0 ) { // 指定した丁度の長さを作れなかった。 ; } else if ( len == 0 ) { // 指定した長さを作れたので答えを表示。 for( int i = 0 ; i < n ; i++ ) { printf( "%d " , array[ i ] ) ; } printf( "\n" ) ; } else { // 問題を一つ小さくして再帰。 for( int i = n ; i < size ; i++ ) { swap( &array[ n ] , &array[ i ] ) ; printf( "check( array , %d , %d , %d )\n" , size , len - array[ n ] , n+1 ) ; check( array , size , len - array[ n ] , n + 1 ) ; swap( &array[ i ] , &array[ n ] ) ; } } }
(2) 少ない組み合わせの方がポイントが高い場合には、プログラムをどう変更する?
(3) 答えが1つだけで良い場合は、プログラムをどう変更する?
(4) このプログラムでは、冗長な答えがあるか?ないか?検討せよ。
(5) 前設問の整数比直角三角形のプログラムで、冗長な答えを削除するプログラムを作成せよ。
# ただし、(2)〜(5)は、演習の実験の時間内でできる範囲とする。
Flood fill アルゴリズム
前の問題は、今年度のプログラミングコンテストの課題のパズルとは、方向性が違うので、今年度のプロコンの競技部門に近いパズルネタで演習。(Wikipedia Flood-fill参照)
以下の image のような2次元配列が与えられたら、指定座標(x,y)を中心に周囲を塗りつぶす処理を作成せよ。
include <stdio.h> // *は壁 SPCは白 この領域の指定位置を#で塗りつぶす。 char image1[10][10] = { // (4,4)始点で塗りつぶし後 "*********" , // ********* "* * *" , // * *###* "* * *" , // * *###* "* * *" , // * *####* "*** ***" , // ***###*** "* * *" , // *####* * "* * *" , // *###* * "* * *" , // *###* * "*********" , // ********* } ; char image2[10][10] = { // 応用問題用の画像例 "*********" , // * のような隙間は通り抜けられる "* * *" , // * ようにするにはどうすればいい? "* ** *" , // ** "* ** *" , // ** これは通り抜けられない "*** ***" , // ** "* * *" , "* * *" , "* * *" , "*********" , } ; // 盤面を表示 void print_image( char image[10][10] ) { for( int y = 0 ; y < 9 ; y++ ) { for( int x = 0 ; x < 9 ; x++ ) { printf( "%c" , image[y][x] ) ; } printf( "\n" ) ; } } // 再帰呼び出しを使った flud_fill アルゴリズム void flood_fill( char image[10][10] , int x , int y , char fill ) { // 指定座標が空白なら if ( image[y][x] == ' ' ) { // その座標を埋める image[y][x] = fill ; ////////////////////////////////////// // ここに周囲をflud_fillする処理を書く // ////////////////////////////////////// } } int main() { print_image( image1 ) ; flood_fill( image1 , 4 , 4 , '#' ) ; print_image( image1 ) ; return 0 ; }
応用問題
Wikipediaのflood-fill のプログラムの説明のアルゴリズムでは、左図黒のような斜めに並んだブロックは、境界として通り抜けられないようにつくられている。
そこで、斜めに並んだブロックは通り抜けられるルールとした場合のプログラムを記述せよ。
予備実験1 データベースの操作
データベースの基本操作
- SQL演習環境(学内からのみアクセス可能)
- SQLの基本(DB授業資料) — (create table,insert,select まで)
- SQLと結合(DB授業資料) — (where節から串刺し検索まで)
データベースをWebから操作
練習問題
- 上記の db_query.php を改良して、ユーザ名を入力してもらい、その名前のデータを表示するプログラムに改造する。
- おなじく、年齢を入力したら、指定した年齢以上の人のデータを表示するプログラムに改良する。
創造工学演習・予備実験(SQLとPHP)
先週のPHPの予備実験に引き続き、データベースの説明とそのプログラムで演習を行う。
<?php // データの保存先 $dbfile = "/home/guests/guest0/public_data/tsaitoh.db" ; if ( !file_exists( $dbfile ) ) { // データベースの宣言と初期化 $db = new SQLite3( $dbfile ) ; $cmd = "create table nametel ( name char( 20 ) , phone char( 20 ) ) ;" ."insert into nametel ( name , phone ) values ( 't-saitoh' , '090-1111-1111' ) ;" ."insert into nametel ( name , phone ) values ( 'tomoko' , '090-2222-2222' ) ;" ."insert into nametel ( name , phone ) values ( 'mitsuki' , '090-3333-3333' ) ;" ."insert into nametel ( name , phone ) values ( 'ayuka' , '090-4444-4444' ) ;" ; if ( $db->exec( $cmd ) ) { print "Success.\n" ; } else { print "Fail\n" ; } $db = null ; } ?> <html> <head> <title></title> </head> <body> <?php // 警告表示の抑止 ini_set( 'error_reporting' , E_WARNING ) ; // データベース処理(検索処理) $db = new SQLite3( $dbfile ) ; $id = $_REQUEST[ "name" ] ; if ( $db !== FALSE && $id != "" ) { // SQL命令の生成(インジェクションの危険性指摘は別述) $cmd = "select * from nametel where name='$id' ;" ; print $cmd ; // 問い合わせの実行 $result = $db->query( $cmd ) ; print "<table border='1'>\n" ; print "<tr><td>name</td><td>phone</td></tr>" ; while( ($row = $result->fetchArray( SQLITE3_BOTH )) !== FALSE ) { print "<tr>" ."<td>".$row[0]."</td>" ."<td>".$row[1]."</td>" ."</tr>\n" ; } print "</table>\n" ; } ?> <form method="post" action="sql.php"> <input type="text" name="name" /> <input type="submit" value="exec" /> </form> <?php // データベース登録処理 $newname = $_REQUEST[ "newname" ] ; $newphone = $_REQUEST[ "newphone" ] ; if ( $newname != "" && $newphone != "" ) { // データ登録用SQL $cmd = "insert into nametel ( name , phone ) values ( '$newname' , '$newphone' ) ;" ; // データ登録 $db->exec( $cmd ) ; print "$newname さんの電話番号 $newphone を登録しました" ; } ?> <form method="post" action="sql.php"> <input type="text" name="newname" /> <input type="text" name="newphone" /> <input type="submit" value="exec" /> </form> </body> </html>
SQLとPHP
SQLとPHPのプログラムの練習。
SQLの基礎
簡単にSQLの文法を勉強したあと、自分で簡単なデータベースを作り検索してみる。 Windowsのエディタで、SQLの命令を入力し、 ブラウザの実験環境のSQLの入力フォームの所にコピー&ペーストで実験する。
PHPでデータベースを読みだす
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" id="sixapart-standard"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body> <h1>SQLの実験</h1> <form method="GET" action="sample.php"> <input type="text" name="A" /> <input type="submit" value="QUERY" /> </form> <?php // SQLのデータベースファイル $DBFILE = "説明で聞いたファイルの場所を記載/名前.db" ; // フォームの値をもらう $a = $_REQUEST[ "A" ] ; // データベースを開く $db = new SQLite3( "$DBFILE" ) ; // 実行したいSQL $sql = "select * from S where 業者番号='$a' ;" ; // SQL実行 if ( ($query = $db->query( $sql )) !== FALSE ) { // SQL実行に成功 print "<pre>" ; print '$a'." = $a\n" ; // 1件づつ全部読み込み while( ($res=$query->fetchArray(SQLITE3_ASSOC)) !== FALSE ) { // 1行分のデータの配列の全要素の繰り返し // $res[0],$res[1],... foreach( $res as $key => $value ) { print "$key=$value " ; } print "\n" ; } print "</pre>" ; } ?> </body> </html>
アイデアをまとめる方法
4EIの創造工学演習で、今日はアイデア出し。 といっても、発散しがちなアイデアを形にするのは難しい。 一般的な手法を以下にまとめる。
一般的には、アイデアを発散させ、その後一旦アイデアを評価して絞込む。 そしてそのアイデアをより良いものに変えていく。 参考 SlideShareより
KJ法
KJ法: テーマに関するアイデアをカードに書き出し、ある程度出揃ったら似たアイデアを集めてタイトルをつける。 さらに似たものを集めてタイトルをつけ、アイデアをまとめていく。

マインドマップ
マインドマップとは、 最初に掲げたテーマを中心に、発想したキーワードを周囲に書き並べる。さらに、その発想キーワードの周りにさらなる発想、問題点、利点などを キーワード的に書き並べ、ある程度発散してきたら、関連するものを結びつけていく。

マインドマップは、専用のエディタなどもあるので、そういうツールを使うのもあり。