{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"name":"Week07.ipynb","provenance":[],"authorship_tag":"ABX9TyPXqFOQ+cSCubUfP3ly5F64"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["#第七週上課內容"],"metadata":{"id":"9xoK4OIjIfZA"}},{"cell_type":"markdown","source":["###GitHub 教材參考資料\n","\n","1. [https://github.com/htchen/i2p-nthu/blob/master/程式設計一/function/function.md](https://github.com/htchen/i2p-nthu/blob/master/%E7%A8%8B%E5%BC%8F%E8%A8%AD%E8%A8%88%E4%B8%80/function)\n","\n","2. [https://github.com/htchen/i2p-nthu/tree/master/程式設計一/Recursive](https://github.com/htchen/i2p-nthu/tree/master/%E7%A8%8B%E5%BC%8F%E8%A8%AD%E8%A8%88%E4%B8%80/Recursive)\n"],"metadata":{"id":"05G1Fqg6GRZX"}},{"cell_type":"markdown","source":["##Example 1\n","用遞迴方式計算最大公因數"],"metadata":{"id":"mviKuWaapY32"}},{"cell_type":"code","source":["%%writefile E07_01.c\n","#include <stdio.h>\n","int gcd(int a, int b);\n","int main(void)\n","{\n","\tint x, y;\n","\tscanf(\"%d%d\", &x, &y);\n","\tprintf(\"gcd(%d, %d) = %d\\n\", x, y, gcd(x, y));\n","  return 0;\n","}\n","int gcd(int a, int b)\n","{\n","\tif (b==0) {\n","\t\treturn a;\n","\t} else { \n","\t\treturn gcd(b, a%b);\n","\t} \n","}"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"7ZODSFC-pmP2","executionInfo":{"status":"ok","timestamp":1648551356966,"user_tz":-480,"elapsed":273,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"c4b0fad5-d747-421a-e55e-141e6c972f8a"},"execution_count":7,"outputs":[{"output_type":"stream","name":"stdout","text":["Overwriting E07_01.c\n"]}]},{"cell_type":"code","source":["%%shell\n","gcc E07_01.c -o E07_01\n","./E07_01"],"metadata":{"id":"HMqFdYymQIzj","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1648551367195,"user_tz":-480,"elapsed":7414,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"5276e0da-8264-4aaf-966c-47b0f28c75dd"},"execution_count":8,"outputs":[{"output_type":"stream","name":"stdout","text":["210 36\n","gcd(210, 36) = 9\n"]},{"output_type":"execute_result","data":{"text/plain":[""]},"metadata":{},"execution_count":8}]},{"cell_type":"markdown","source":["##Example 2\n","三座城堡問題：\n","在 3x3 的棋盤上擺三個城堡。\n","城堡只能走水平或垂直方向，可以吃掉在同一條水平或垂直線上的其他棋子。所以每個 row 只能擺一個城堡。\n","\n","修改底下的程式碼，使得最後只輸出滿足互不衝突、互不吃掉對方的擺法。"],"metadata":{"id":"Mp5lAOxDodYd"}},{"cell_type":"code","source":["%%writefile E07_02.c\n","#include <stdio.h>\n","int board[11][11];\n","void place(int row, int size);\n","void show_board(int size)\n","{\n","\tint i, j;\n","\tfor (i=1; i<=size; i++) {\n","\t\tfor (j=1; j<=size; j++) {\n","\t\t\tif (board[i][j]==0) {\n","\t\t\t  printf(\"O\");\n","\t\t\t} else {\n","\t\t\t\t\tprintf(\"#\");\n","\t\t\t}\n","\t\t}\n","\t\tprintf(\"\\n\");\n","\t}\n","\tprintf(\"\\n\");\n","}\n","int main(void)\n","{\n","\tplace(1, 9);\n","\treturn 0;\n","}\n","int is_valid(int row, int i)\n","{\n","\t\tint j;\n","\t  for (j=row-1; j>=1; j--) {\n","\t\t\t\tif (board[j][i]==1) {\n","\t\t\t\t\t\treturn 0;\n","\t\t\t\t}\n","\t\t}\n","\t\treturn 1;\n","}\n","void place(int row, int size)\n","{\n","\tint i;\n","\tif (row>size) {\n","\t\tshow_board(size);\n","\t} else {\n","\t\tfor (i=1; i<=size; i++) {\n","\t\t\tif (is_valid(row, i)) {\n","\t\t\t\tboard[row][i] = 1;\n","\t\t\t\tplace(row+1, size);  \n","\t\t\t\tboard[row][i] = 0;\n","\t\t\t}\n","\t\t}\n","\t}\n","}\n","\n","/*\n","0 1 0  row=1, i=1\n","0 0 0  row=2, i=1\n","0 0 0  row=3, i=2\n","*/"],"metadata":{"id":"LZ8575uZo5hG","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1648554720866,"user_tz":-480,"elapsed":379,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"a00652cf-211f-40bf-a150-5ded54906399"},"execution_count":26,"outputs":[{"output_type":"stream","name":"stdout","text":["Overwriting E07_02.c\n"]}]},{"cell_type":"code","source":["%%shell\n","gcc E07_02.c -o E07_02\n","./E07_02\n"],"metadata":{"id":"f1ClwjOzsdsQ"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["三座城堡 sample code https://gist.github.com/htchen/e86a7d4293d6b33e2dce\n"],"metadata":{"id":"XK_DGBYvpFt1"}},{"cell_type":"markdown","source":["##Exercise 1\n","\n","**Four Queens**\n","\n","原版的經典問題是將八個皇后放在西洋棋棋盤上 [Wikipedia](http://en.wikipedia.org/wiki/Eight_queens_puzzle)\n","\n","任兩個皇后都不能在同一水平線或垂直線或45度線上，否則就會吃掉對方。也就是說，棋盤中任何橫列、直行、以及斜線都只能有一個皇后。\n","\n","我們先考慮四個皇后的情況。\n","請修改範例程式，算出所有可能的放置方式。\n","\n","譬如，四個皇后放在4x4的棋盤上，只有下面兩種擺法：\n","```\n","O@OO\n","OOO@\n","@OOO\n","OO@O\n","..........\n","OO@O\n","@OOO\n","OOO@\n","O@OO\n","..........\n","```\n","\n","上面第一種擺法可以用 `1, 3, 0, 2` 表示，\n","代表 `row 0` 的皇后放在 `column 1` 的位置，`row 1` 皇后放在 `column 3`，`row 2` 皇后放在 `column 0`，`row 3` 皇后放在 `column 2`。\n","\n","同理，第二種擺法可以用 `2, 0, 3, 1` 表示。\n","\n","請修改範例程式，讓它能輸出上面的結果，並且試著把 `NQ` 改成 `6`，看看能否得到下面四種擺法。\n","```\n","O@OOOO\n","OOO@OO\n","OOOOO@\n","@OOOOO\n","OO@OOO\n","OOOO@O\n","..........\n","OO@OOO\n","OOOOO@\n","O@OOOO\n","OOOO@O\n","@OOOOO\n","OOO@OO\n","..........\n","OOO@OO\n","@OOOOO\n","OOOO@O\n","O@OOOO\n","OOOOO@\n","OO@OOO\n","..........\n","OOOO@O\n","OO@OOO\n","@OOOOO\n","OOOOO@\n","OOO@OO\n","O@OOOO\n","..........\n","```\n","\n","以底下的程式碼為基礎，把缺少的部分補上："],"metadata":{"id":"2HgZZI7vpHFE"}},{"cell_type":"code","source":["%%writefile W07_01.c\n","#include <stdio.h>\n","#define NQ 8\n","\n","/* q[i] 記錄的是在第 i 列 (row) 出現的皇后，要擺在第幾行 (column) */\n","/* 譬如，q[] 的內容如果是 {2, 0, 3, 1}，表示四個皇后分別放在棋盤的 (0,2), (1,0), (2,3), (3,1) 四個位置 */\n","\n","int q[NQ] = {0};\n","\n","void place(int row);\n","int valid(int row, int col);\n","void display(void);\n","\n","int main(void)\n","{\n","\tplace(0);\n","\treturn 0;\n","}\n","\n","/*\n","判斷目前的狀況下，如果在 row, col 位置放入新的皇后\n","是否會和之前的皇后衝突\n","如果是合法的放置方式 return 1;\n","如果有衝突 return 0;\n","*/\n","int valid(int row, int col)\n","{\n","\tint i;\n","\tfor (i=0; i<=row-1; i++) {\n","\t\tif ( q[i]==col || row-i == col-q[i] || row-i == q[i]-col) {\n","\t\t  return 0;\n","\t\t}\n","\t}\n","\treturn 1;\n","}\n","\n","void display(void)\n","{\n","\tint i, j;\n","\tfor (i=0; i<NQ; ++i) {\n","\t\t\tfor (j=0; j<NQ; ++j) {\n","\t\t\t\t\tif (q[i] == j) {\n","\t\t\t\t\t\t\tprintf(\"@\");\n","\t\t\t\t\t} else {\n","\t\t\t\t\t\t\tprintf(\"o\");\n","\t\t\t\t\t}\n","\t\t\t}\n","\t\t\tprintf(\"\\n\");\n","\t}\n","\tprintf(\"--------------------\\n\");\n","}\n","\n","void place(int row)\n","{\n","\tint j;\n","\tif (row == NQ) {\n","\t\tdisplay();\n","\t} else {\n","\t\tfor (j=0; j<NQ; j++) {\n","\t\t\tif (valid(row, j)) {\n","\t\t\t\tq[row] = j;\n","\t\t\t\tplace(row+1);\n","\t\t\t}\n","\t\t}\n","\t}\n","}\n"],"metadata":{"id":"1rqwHlHmrEi9","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1648557606066,"user_tz":-480,"elapsed":278,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"77ee05d6-4e76-48e5-b457-b2c83c300cea"},"execution_count":40,"outputs":[{"output_type":"stream","name":"stdout","text":["Overwriting W07_01.c\n"]}]},{"cell_type":"code","source":["%%shell\n","gcc W07_01.c -o W07_01\n","./W07_01"],"metadata":{"id":"3yZlwmmjsiKP"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["四個皇后 sample code https://gist.github.com/htchen/f0082a35ff9d04231cfd"],"metadata":{"id":"vFIdo3PBrPPI"}},{"cell_type":"markdown","source":["##Exercise 2\n","\n","**Make Change**\n","\n","輸入不同面值的銅板，然後輸入一個金額，將全部可能的找零方式列出。\n","\n","譬如有 1 元、5元、10元銅板，\n","要湊出 17 元，如果將可能的組合表示成 `\"(1元個數,5元個數,10元個數)\"`，總共會有下列幾種方法：\n","```\n","(2,1,1)\n","(2,3,0)\n","(7,0,1)\n","(7,2,0)\n","(12,1,0)\n","(17,0,0)\n","```\n","\n","我們可以用 *遞迴* 方式來看待這個問題：\n","首先依序考慮使用 1元、5元、10元的情況。\n","假設現在我們手邊有 `M` 元需要換成銅板，\n","從 1 元開始考慮，\n","我們可以把問題區分成兩種可能：\n","1. 使用 1 元，因此狀態變成手邊有 `M-1` 元，然後試著繼續用 1 元、5元、10元來湊。\n","2. 完全不使用 1，因此狀態變成手邊還是有 `M` 元，但是只考慮用 5元 和 10元來湊。\n","\n","以上兩種可能都可以讓問題簡化，\n","第一種是讓錢變少，另一種則是讓需要考慮的銅板面值變少。\n","\n","用這樣的方式繼續簡化下去，\n","只會需要可慮幾種結束方式：\n","1. 手邊剩下 0 元，表示成功湊出組合。\n","2. 手邊剩下 `M` 元，`M<0`，表示這樣的組合不可能湊出需要的金額。\n","3. 沒有任何可用的銅板面額可供組合。\n","\n","其餘情況就繼續遞迴。\n","\n","底下是未完成的程式碼："],"metadata":{"id":"7co6TxbjrUL2"}},{"cell_type":"code","source":["%%writefile W07_02.c\n","#include <stdio.h>\n","#define MAXNV 5                  //0  1  2  \n","int values[MAXNV]; // values[] = {1, 5, 10};\n","int numbers[MAXNV];// numbers[] = {2, 1, 1};\n","\n","void show(int nv);\n","void change(int amount, int smallest_idx, int nv);\n","\n","int main(void)\n","{\n","\tint nv, i;\n","\tint money;\n","\n","\tscanf(\"%d\", &nv);\n","\tif (nv>MAXNV || nv<1) return 0;\n","\n","\tfor (i=0; i<nv; i++) {\n","\t\tscanf(\"%d\", &values[i]);  // 1 5 10\n","\t}\n","\n","\tscanf(\"%d\", &money);  // 17\n","\tchange(money, 0, nv); // change(17, 0, 3);\n","\n","\treturn 0;\n","}\n","\n","void show(int nv)\n","{\n","\tint i;\n","\tprintf(\"(%d\", numbers[0]);\n","\tfor (i=1; i<nv; i++) {\n","\t\tprintf(\",%d\", numbers[i]);\n","\t}\n","\tprintf(\")\\n\");\n","}\n","\n","void change(int amount, int smallest_idx, int nv)\n","{\n","\tif (smallest_idx<nv) {\n","\t\tif (amount == 0) {\n","\t\t\tshow(nv);\n","\t\t} else if (amount > 0) {\n","\t\t\t// do not use the smallest valued coin \n","\t\t\tchange(amount, smallest_idx+1, nv);\n","\t\t\t// use one coin of the smallest value\n","\t\t\tnumbers[smallest_idx] += 1;\n","\t\t\tchange(amount-values[smallest_idx], smallest_idx, nv);\n","\t\t\tnumbers[smallest_idx] -= 1;\n","\t\t}\n","\t}\n","}"],"metadata":{"id":"bNrwKmsysNfy","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1648560151230,"user_tz":-480,"elapsed":292,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"11853650-3645-4f2d-9ac0-962f3bf2834e"},"execution_count":51,"outputs":[{"output_type":"stream","name":"stdout","text":["Overwriting W07_02.c\n"]}]},{"cell_type":"markdown","source":["測試底下的輸入輸出範例。\n","\n","輸入:\n","``` \n","3\n","1 5 10\n","17\n","```\n","第一個數字代表有幾種不同面值的銅板，\n","接下來就是對應的銅板面值，\n","最後一個數字是要找零的金額。\n","\n","輸出:\n","```\n","(2,1,1)\n","(2,3,0)\n","(7,0,1)\n","(7,2,0)\n","(12,1,0)\n","(17,0,0)\n","```"],"metadata":{"id":"sr3iiC0Ys2zq"}},{"cell_type":"code","source":["%%shell\n","gcc W07_02.c -o W07_02\n","./W07_02"],"metadata":{"id":"puvNtlHWssLK","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1648560246505,"user_tz":-480,"elapsed":16231,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"536272e3-4654-4e5c-c22e-0cb19b45a9b1"},"execution_count":54,"outputs":[{"output_type":"stream","name":"stdout","text":["3\n","10 5 1\n","17\n","(0,0,17)\n","(0,1,12)\n","(0,2,7)\n","(0,3,2)\n","(1,0,7)\n","(1,1,2)\n"]},{"output_type":"execute_result","data":{"text/plain":[""]},"metadata":{},"execution_count":54}]},{"cell_type":"markdown","source":["換銅板 sample code https://gist.github.com/htchen/1613e9c8835f90b7b009"],"metadata":{"id":"WixOMTcEtF5p"}},{"cell_type":"markdown","source":["##Exercise 3\n","\n","**N Queens**\n","\n","將 `N` 個皇后放在西洋棋棋盤上，\n","棋盤中任何橫列、直行、以及斜線都只能有一個皇后，\n","算出有幾種合法的放置方式，若無解則答案為 `0`。\n"],"metadata":{"id":"eAEfEJkitIw9"}},{"cell_type":"code","source":["%%writefile W07_03.c\n","#include <stdio.h>\n","#define MAX 12\n","/* q[i] 記錄的是在第 i 列 (row) 出現的皇后，要擺在第幾行 (column) */\n","/* 譬如，q[] 的內容如果是 {2, 0, 3, 1}，表示四個皇后分別放在棋盤的\n","(0,2), (1,0), (2,3), (3,1) 四個位置 */\n","int q[MAX] = {0};\n","int N;\n","void place(int row);\n","int valid(int row, int col);\n","int main(void)\n","{\n","\tscanf(\"%d\", &N);\n","\tplace(0);\n","\t/* printf(???); */\n","\treturn 0;\n","}\n","/* 判斷目前的狀況下，如果在 row, col 位置放入新的皇后 是否會和之前的皇后衝突 如果是合法的放置方式 return 1; 如果有衝突 return 0; */\n","int valid(int row, int col)\n","{\n","\tint i;\n","\tfor (i=0; i<=row-1; i++) {\n","\t\t/* if ( ??? ) return 0; */\n","\t}\n","\treturn 1;\n","}\n","void place(int row)\n","{\n","\tint j;\n","\tif (row == N) {\n","\t\t/* ??? */\n","\t} else {\n","\t\tfor (j=0; j<N; j++) {\n","\t\t\tif (valid(row, j)) {\n","\t\t\t\t/* ??? */\n","\t\t\t}\n","\t\t}\n","\t}\n","}"],"metadata":{"id":"CUD4U1iTuWSa"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["*Input*\n","```\n","N\n","N 為 1~12 的正整數\n","```\n","\n","*Output*\n","```\n","有幾種擺法\n","(不須加換行)\n","```\n","\n","*Sample Input*\n","```\n","8\n","```\n","\n","*Sample Output*\n","```\n","92\n","```"],"metadata":{"id":"t8e2YmcUujMQ"}},{"cell_type":"code","source":["%%shell\n","gcc W07_03.c -o W07_03\n","./W07_03"],"metadata":{"id":"dn61T8gVudiD"},"execution_count":null,"outputs":[]}]}