概要
アルゴリズムの学習記録を投稿します。
今回は蟻本・グラフ・最小全域木のプリム法についてです。
問題
全域木の最小コストを求めよ。
入力
graph1 = [
[INF,1,INF,INF,INF,INF,INF],
[1,INF,3,INF,7,INF,2],
[INF,3,INF,5,1,INF,INF],
[INF,INF,5,INF,8,INF,INF],
[INF,7,1,8,INF,5,INF],
[INF,INF,INF,INF,5,INF,10],
[INF,2,INF,INF,INF,10,INF]
]
vertexCount = 5
出力
17
※問題文は本には書かれていないので 入力と出力は自分がわかりやすいように書きました。
コード部分
//
/**最小全域木 プリム法 蟻本 p100
*
* @param graph{Array} 無向グラフ 隣接行列
* @param vertexCount{Number} 頂点の数
* @return {Number} 最小コスト
*/
const prim = (graph,vertexCount) =>{
let INF = 1000;
// 初期化
let used = new Array(vertexCount).fill(false);
let mincosts = new Array(vertexCount).fill(INF); //最短経路
let res = 0;
mincosts[0] = 0;
let loopCount = 0;
console.log(`loopCount|u|v|used|res|条件|結果`);
console.log(`---------|-|-|----|---|----|---`);
while(true){
let v = -1;
for(let u=0; u<vertexCount; u++){
// 最小となる頂点を探す
if(!used[u] && (v == -1 || mincosts[u] < mincosts[v])) {
loopCount++;
v = u;
console.log(`${loopCount}|${u}|${v}|${used}|${res}|最小となる頂点を探す </br>!used[u] && (v == -1 or mincosts[u] < mincosts[v]) </br>${!used[u]} and (${v} =1 )| ${mincosts[u]} < ${mincosts[v]}`);
}
}
if(v == -1) break;
used[v] = true;
res += mincosts[v];
for(let u = 0;u < vertexCount; u++){
loopCount++;
mincosts[u] = Math.min(mincosts[u], graph[v][u]);
console.log(`${loopCount}|${u}|${v}|${used}|${res}|最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])</br>${mincosts[u]} = Math.min(${mincosts[v]},${graph[v][u]})`);
}
}
return res;
}
let INF = 1000;
let graph1 = [[INF,1,INF,INF,INF,INF,INF],
[1,INF,3,INF,7,INF,2],
[INF,3,INF,5,1,INF,INF],
[INF,INF,5,INF,8,INF,INF],
[INF,7,1,8,INF,5,INF],
[INF,INF,INF,INF,5,INF,10],
[INF,2,INF,INF,INF,10,INF]
]
// 17
prim(graph1,7)
python tutor
コードを実際に動かせるwebサイト
ステップ実行かつステップ事の変数を確認できる特徴があります。
その他情報
感想
問題文がないからそれがちょっと手間だったんだよなぁ…
入力値を考えるのに時間かかった
依存関係グラフ
依存関係グラフは変数の結びつきを一目でわかりやすくするための図です。
変数の流れを確認しやすくすることでワーキングメモリの負担を減らすことができます。
作成方法はコード上の変数に丸付けて線を繋げています。
状態遷移図
計算内容を明示する表。
ステップごとの変数の値を各列に表示します。
複雑な計算を行うコードを理解するのに役立つ表です。
蟻本の値
loopCount | u | v | used | res | 条件 | 結果 |
---|---|---|---|---|---|---|
1 | 0 | 0 | false,false,false,false,false,false,false | 0 | 最小となる頂点を探す !used[u] && (v == -1 or mincosts[u] < mincosts[v]) true and (0 =1 ) | 0 < 0 |
2 | 0 | 0 | true,false,false,false,false,false,false | 0 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])0 = Math.min(0,1000) |
3 | 1 | 0 | true,false,false,false,false,false,false | 0 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(0,1) |
4 | 2 | 0 | true,false,false,false,false,false,false | 0 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1000 = Math.min(0,1000) |
5 | 3 | 0 | true,false,false,false,false,false,false | 0 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1000 = Math.min(0,1000) |
6 | 4 | 0 | true,false,false,false,false,false,false | 0 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1000 = Math.min(0,1000) |
7 | 5 | 0 | true,false,false,false,false,false,false | 0 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1000 = Math.min(0,1000) |
8 | 6 | 0 | true,false,false,false,false,false,false | 0 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1000 = Math.min(0,1000) |
9 | 1 | 1 | true,false,false,false,false,false,false | 0 | 最小となる頂点を探す !used[u] && (v == -1 or mincosts[u] < mincosts[v]) true and (1 =1 ) | 1 < 1 |
10 | 0 | 1 | true,true,false,false,false,false,false | 1 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])0 = Math.min(1,1) |
11 | 1 | 1 | true,true,false,false,false,false,false | 1 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(1,1000) |
12 | 2 | 1 | true,true,false,false,false,false,false | 1 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])3 = Math.min(1,3) |
13 | 3 | 1 | true,true,false,false,false,false,false | 1 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1000 = Math.min(1,1000) |
14 | 4 | 1 | true,true,false,false,false,false,false | 1 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])7 = Math.min(1,7) |
15 | 5 | 1 | true,true,false,false,false,false,false | 1 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1000 = Math.min(1,1000) |
16 | 6 | 1 | true,true,false,false,false,false,false | 1 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])2 = Math.min(1,2) |
17 | 2 | 2 | true,true,false,false,false,false,false | 1 | 最小となる頂点を探す !used[u] && (v == -1 or mincosts[u] < mincosts[v]) true and (2 =1 ) | 3 < 3 |
18 | 6 | 6 | true,true,false,false,false,false,false | 1 | 最小となる頂点を探す !used[u] && (v == -1 or mincosts[u] < mincosts[v]) true and (6 =1 ) | 2 < 2 |
19 | 0 | 6 | true,true,false,false,false,false,true | 3 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])0 = Math.min(2,1000) |
20 | 1 | 6 | true,true,false,false,false,false,true | 3 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(2,2) |
21 | 2 | 6 | true,true,false,false,false,false,true | 3 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])3 = Math.min(2,1000) |
22 | 3 | 6 | true,true,false,false,false,false,true | 3 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1000 = Math.min(2,1000) |
23 | 4 | 6 | true,true,false,false,false,false,true | 3 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])7 = Math.min(2,1000) |
24 | 5 | 6 | true,true,false,false,false,false,true | 3 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])10 = Math.min(2,10) |
25 | 6 | 6 | true,true,false,false,false,false,true | 3 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])2 = Math.min(2,1000) |
26 | 2 | 2 | true,true,false,false,false,false,true | 3 | 最小となる頂点を探す !used[u] && (v == -1 or mincosts[u] < mincosts[v]) true and (2 =1 ) | 3 < 3 |
27 | 0 | 2 | true,true,true,false,false,false,true | 6 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])0 = Math.min(3,1000) |
28 | 1 | 2 | true,true,true,false,false,false,true | 6 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(3,3) |
29 | 2 | 2 | true,true,true,false,false,false,true | 6 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])3 = Math.min(3,1000) |
30 | 3 | 2 | true,true,true,false,false,false,true | 6 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])5 = Math.min(3,5) |
31 | 4 | 2 | true,true,true,false,false,false,true | 6 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(3,1) |
32 | 5 | 2 | true,true,true,false,false,false,true | 6 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])10 = Math.min(3,1000) |
33 | 6 | 2 | true,true,true,false,false,false,true | 6 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])2 = Math.min(3,1000) |
34 | 3 | 3 | true,true,true,false,false,false,true | 6 | 最小となる頂点を探す !used[u] && (v == -1 or mincosts[u] < mincosts[v]) true and (3 =1 ) | 5 < 5 |
35 | 4 | 4 | true,true,true,false,false,false,true | 6 | 最小となる頂点を探す !used[u] && (v == -1 or mincosts[u] < mincosts[v]) true and (4 =1 ) | 1 < 1 |
36 | 0 | 4 | true,true,true,false,true,false,true | 7 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])0 = Math.min(1,1000) |
37 | 1 | 4 | true,true,true,false,true,false,true | 7 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(1,7) |
38 | 2 | 4 | true,true,true,false,true,false,true | 7 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(1,1) |
39 | 3 | 4 | true,true,true,false,true,false,true | 7 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])5 = Math.min(1,8) |
40 | 4 | 4 | true,true,true,false,true,false,true | 7 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(1,1000) |
41 | 5 | 4 | true,true,true,false,true,false,true | 7 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])5 = Math.min(1,5) |
42 | 6 | 4 | true,true,true,false,true,false,true | 7 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])2 = Math.min(1,1000) |
43 | 3 | 3 | true,true,true,false,true,false,true | 7 | 最小となる頂点を探す !used[u] && (v == -1 or mincosts[u] < mincosts[v]) true and (3 =1 ) | 5 < 5 |
44 | 0 | 3 | true,true,true,true,true,false,true | 12 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])0 = Math.min(5,1000) |
45 | 1 | 3 | true,true,true,true,true,false,true | 12 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(5,1000) |
46 | 2 | 3 | true,true,true,true,true,false,true | 12 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(5,5) |
47 | 3 | 3 | true,true,true,true,true,false,true | 12 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])5 = Math.min(5,1000) |
48 | 4 | 3 | true,true,true,true,true,false,true | 12 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(5,8) |
49 | 5 | 3 | true,true,true,true,true,false,true | 12 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])5 = Math.min(5,1000) |
50 | 6 | 3 | true,true,true,true,true,false,true | 12 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])2 = Math.min(5,1000) |
51 | 5 | 5 | true,true,true,true,true,false,true | 12 | 最小となる頂点を探す !used[u] && (v == -1 or mincosts[u] < mincosts[v]) true and (5 =1 ) | 5 < 5 |
52 | 0 | 5 | true,true,true,true,true,true,true | 17 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])0 = Math.min(5,1000) |
53 | 1 | 5 | true,true,true,true,true,true,true | 17 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(5,1000) |
54 | 2 | 5 | true,true,true,true,true,true,true | 17 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(5,1000) |
55 | 3 | 5 | true,true,true,true,true,true,true | 17 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])5 = Math.min(5,1000) |
56 | 4 | 5 | true,true,true,true,true,true,true | 17 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(5,5) |
57 | 5 | 5 | true,true,true,true,true,true,true | 17 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])5 = Math.min(5,1000) |
58 | 6 | 5 | true,true,true,true,true,true,true | 17 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])2 = Math.min(5,10) |
その他例1 頂点数4個
入力
graph1 = [
[INF,2,8,20],
[2,INF,1,4],
[8,1,INF,10],
[20,4,10,INF]
]
vertexCount = 4
出力
7
loopCount | u | v | used | res | 条件 | 結果 |
---|---|---|---|---|---|---|
1 | 0 | 0 | false,false,false,false | 0 | 最小となる頂点を探す !used[u] && (v == -1 or mincosts[u] < mincosts[v]) true and (0 =1 ) | 0 < 0 |
2 | 0 | 0 | true,false,false,false | 0 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])0 = Math.min(0,1000) |
3 | 1 | 0 | true,false,false,false | 0 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])2 = Math.min(0,2) |
4 | 2 | 0 | true,false,false,false | 0 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])8 = Math.min(0,8) |
5 | 3 | 0 | true,false,false,false | 0 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])20 = Math.min(0,20) |
6 | 1 | 1 | true,false,false,false | 0 | 最小となる頂点を探す !used[u] && (v == -1 or mincosts[u] < mincosts[v]) true and (1 =1 ) | 2 < 2 |
7 | 0 | 1 | true,true,false,false | 2 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])0 = Math.min(2,2) |
8 | 1 | 1 | true,true,false,false | 2 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])2 = Math.min(2,1000) |
9 | 2 | 1 | true,true,false,false | 2 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(2,1) |
10 | 3 | 1 | true,true,false,false | 2 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])4 = Math.min(2,4) |
11 | 2 | 2 | true,true,false,false | 2 | 最小となる頂点を探す !used[u] && (v == -1 or mincosts[u] < mincosts[v]) true and (2 =1 ) | 1 < 1 |
12 | 0 | 2 | true,true,true,false | 3 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])0 = Math.min(1,8) |
13 | 1 | 2 | true,true,true,false | 3 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(1,1) |
14 | 2 | 2 | true,true,true,false | 3 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(1,1000) |
15 | 3 | 2 | true,true,true,false | 3 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])4 = Math.min(1,10) |
16 | 3 | 3 | true,true,true,false | 3 | 最小となる頂点を探す !used[u] && (v == -1 or mincosts[u] < mincosts[v]) true and (3 =1 ) | 4 < 4 |
17 | 0 | 3 | true,true,true,true | 7 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])0 = Math.min(4,20) |
18 | 1 | 3 | true,true,true,true | 7 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(4,4) |
19 | 2 | 3 | true,true,true,true | 7 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(4,10) |
20 | 3 | 3 | true,true,true,true | 7 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])4 = Math.min(4,1000) |
その他例2 頂点数5個
入力
graph1 = [
[INF,2,8,20,INF],
[2,INF,1,4,INF],
[8,1,INF,10,30],
[20,4,10,INF,5],
[INF,INF,30,5,INF]
]
vertexCount = 5
出力
12
loopCount | u | v | used | res | 条件 | 結果 |
---|---|---|---|---|---|---|
1 | 0 | 0 | false,false,false,false,false | 0 | 最小となる頂点を探す !used[u] && (v == -1 or mincosts[u] < mincosts[v]) true and (0 =1 ) | 0 < 0 |
2 | 0 | 0 | true,false,false,false,false | 0 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])0 = Math.min(0,1000) |
3 | 1 | 0 | true,false,false,false,false | 0 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])2 = Math.min(0,2) |
4 | 2 | 0 | true,false,false,false,false | 0 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])8 = Math.min(0,8) |
5 | 3 | 0 | true,false,false,false,false | 0 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])20 = Math.min(0,20) |
6 | 4 | 0 | true,false,false,false,false | 0 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1000 = Math.min(0,1000) |
7 | 1 | 1 | true,false,false,false,false | 0 | 最小となる頂点を探す !used[u] && (v == -1 or mincosts[u] < mincosts[v]) true and (1 =1 ) | 2 < 2 |
8 | 0 | 1 | true,true,false,false,false | 2 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])0 = Math.min(2,2) |
9 | 1 | 1 | true,true,false,false,false | 2 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])2 = Math.min(2,1000) |
10 | 2 | 1 | true,true,false,false,false | 2 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(2,1) |
11 | 3 | 1 | true,true,false,false,false | 2 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])4 = Math.min(2,4) |
12 | 4 | 1 | true,true,false,false,false | 2 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1000 = Math.min(2,1000) |
13 | 2 | 2 | true,true,false,false,false | 2 | 最小となる頂点を探す !used[u] && (v == -1 or mincosts[u] < mincosts[v]) true and (2 =1 ) | 1 < 1 |
14 | 0 | 2 | true,true,true,false,false | 3 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])0 = Math.min(1,8) |
15 | 1 | 2 | true,true,true,false,false | 3 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(1,1) |
16 | 2 | 2 | true,true,true,false,false | 3 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(1,1000) |
17 | 3 | 2 | true,true,true,false,false | 3 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])4 = Math.min(1,10) |
18 | 4 | 2 | true,true,true,false,false | 3 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])30 = Math.min(1,30) |
19 | 3 | 3 | true,true,true,false,false | 3 | 最小となる頂点を探す !used[u] && (v == -1 or mincosts[u] < mincosts[v]) true and (3 =1 ) | 4 < 4 |
20 | 0 | 3 | true,true,true,true,false | 7 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])0 = Math.min(4,20) |
21 | 1 | 3 | true,true,true,true,false | 7 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(4,4) |
22 | 2 | 3 | true,true,true,true,false | 7 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(4,10) |
23 | 3 | 3 | true,true,true,true,false | 7 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])4 = Math.min(4,1000) |
24 | 4 | 3 | true,true,true,true,false | 7 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])5 = Math.min(4,5) |
25 | 4 | 4 | true,true,true,true,false | 7 | 最小となる頂点を探す !used[u] && (v == -1 or mincosts[u] < mincosts[v]) true and (4 =1 ) | 5 < 5 |
26 | 0 | 4 | true,true,true,true,true | 12 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])0 = Math.min(5,1000) |
27 | 1 | 4 | true,true,true,true,true | 12 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(5,1000) |
28 | 2 | 4 | true,true,true,true,true | 12 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])1 = Math.min(5,30) |
29 | 3 | 4 | true,true,true,true,true | 12 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])4 = Math.min(5,5) |
30 | 4 | 4 | true,true,true,true,true | 12 | 最小コストを求める | mincosts[u] = Math.min(mincosts[u], graph[v][u])5 = Math.min(5,1000) |
参考資料
プログラミングコンテストチャレンジブック [第2版] マイナビ p100-101
プログラマー脳 秀和システム
p73 python tutor
p71 状態遷移表
p69 依存関係グラフ
githubコミット部分