n_toshi max_t p1,1 p1,2 ・・・ p1,max_t // 1 番目の投資先によって得られる利益 p2,1 p2,2 ・・・ p2,max_t // 2 番目の投資先によって得られる利益 ・・・ pn_toshi,1 pn_toshi,2 ・・・ pn_toshi,max_t
3 4 8 18 22 24 // 1 番目の投資先に 1 単位投資するとその利益は 8,2 単位投資するとその利益は 18,・・・ 3 6 9 12 // 2 番目の投資先に 1 単位投資するとその利益は 3,2 単位投資するとその利益は 6,・・・ 6 7 8 10 // ・・・
4 6 2 0 0 0 0 0 // 1 番目の品物の重さは 1 で,その効用は 2 0 0 5 0 0 0 // 2 番目の品物の重さは 3 で,その効用は 5 0 0 4 0 0 0 // 3 番目の品物の重さは 3 で,その効用は 4 0 0 3 0 0 0 // 4 番目の品物の重さは 3 で,その効用は 3
<?php /***************************************************/ /* 動的計画法:資源配分問題(0-1 ナップザック問題)*/ /* ー投資先(品物)毎のデータを出力したい場合ー */ /* coded by Y.Suganuma */ /***************************************************/ // データの入力と領域の確保 fscanf(STDIN, "%d %d", $n_toshi, $max_t); // 投資先数(品物数),最大投資額(最大重量) $max_t++; // 投資を行わない(品物を入れない)場合を含めるため $table = array($n_toshi); // 投資額と利益(重さと効用) $rieki = array($n_toshi); // 投資した際の利益(品物を入れた際の効用) $prev = array($n_toshi); // 前段までの投資額(前段までの重さ) for ($i1 = 0; $i1 < $n_toshi; $i1++) { $table[$i1] = array($max_t); $rieki[$i1] = array($max_t); $prev[$i1] = array($max_t); } for ($i1 = 0; $i1 < $n_toshi; $i1++) { $table[$i1][0] = 0; $str = trim(fgets(STDIN)); $table[$i1][1] = strtok($str, " "); for ($i2 = 2; $i2 < $max_t; $i2++) $table[$i1][$i2] = intval(strtok(" ")); } // 動的計画法 // 初期設定(1段目) for ($i1 = 0; $i1 < $max_t; $i1++) { $rieki[0][$i1] = $table[0][$i1]; $prev[0][$i1] = -1; } // 2段目以降 for ($i1 = 1; $i1 < $n_toshi; $i1++) { for ($i2 = 0; $i2 < $max_t; $i2++) { $rieki[$i1][$i2] = $rieki[$i1-1][$i2]; $prev[$i1][$i2] = $prev[$i1-1][$i2]; } for ($i2 = 0; $i2 < $max_t; $i2++) { for ($i3 = 0; $i2+$i3 < $max_t; $i3++) { if ($rieki[$i1-1][$i3]+$table[$i1][$i2] > $rieki[$i1][$i2+$i3]) { $rieki[$i1][$i2+$i3] = $rieki[$i1-1][$i3]+$table[$i1][$i2]; $prev[$i1][$i2+$i3] = $i3; } } } } // 結果の出力 $k = -1; $max = -1; for ($i1 = 0; $i1 < $max_t ; $i1++) { if ($rieki[$n_toshi-1][$i1] > $max) { $max = $rieki[$n_toshi-1][$i1]; $k = $i1; } } printf("最大利益(最大効用) %d\n", $max); for ($i1 = $n_toshi-1; $i1 > 0; $i1--) { $k1 = 0; if ($rieki[$i1][$k] != $rieki[$i1-1][$k]) { $k1 = $k - $prev[$i1][$k]; $k = $prev[$i1][$k]; } printf(" 投資先(品物) %d 投資単位(重さ) %d 利益(効用) %d\n", $i1+1, $k1, $table[$i1][$k1]); } printf(" 投資先(品物) 1 投資単位(重さ) %d 利益(効用) %d\n", $k, $table[0][$k]); ?>
<?php /***************************************************/ /* 動的計画法:資源配分問題(0-1 ナップザック問題)*/ /* ー投資先(品物)毎のデータを必要としない場合ー */ /* coded by Y.Suganuma */ /***************************************************/ // データの入力と領域の確保 fscanf(STDIN, "%d %d", $n_toshi, $max_t); // 投資先数(品物数),最大投資額(最大重量) $max_t++; // 投資を行わない(品物を入れない)場合を含めるため $table = array($n_toshi); // 投資額と利益(重さと効用) $rieki = array(2); // 投資した際の利益(品物を入れた際の効用) for ($i1 = 0; $i1 < $n_toshi; $i1++) $table[$i1] = array($max_t); for ($i1 = 0; $i1 < 2; $i1++) $rieki[$i1] = array($max_t); for ($i1 = 0; $i1 < $n_toshi; $i1++) { $table[$i1][0] = 0; $str = trim(fgets(STDIN)); $table[$i1][1] = strtok($str, " "); for ($i2 = 2; $i2 < $max_t; $i2++) $table[$i1][$i2] = intval(strtok(" ")); } // 動的計画法 // 初期設定(1段目) $k1 = 0; $k2 = 1; for ($i1 = 0; $i1 < $max_t; $i1++) $rieki[0][$i1] = $table[0][$i1]; // 2段目以降 for ($i1 = 1; $i1 < $n_toshi; $i1++) { for ($i2 = 0; $i2 < $max_t; $i2++) $rieki[$k2][$i2] = $rieki[$k1][$i2]; for ($i2 = 0; $i2 < $max_t; $i2++) { for ($i3 = 0; $i2+$i3 < $max_t; $i3++) { if ($rieki[$k1][$i3]+$table[$i1][$i2] > $rieki[$k2][$i2+$i3]) $rieki[$k2][$i2+$i3] = $rieki[$k1][$i3]+$table[$i1][$i2]; } } $k1++; $k1 %= 2; $k2++; $k2 %= 2; } // 結果の出力 $max = -1; for ($i1 = 0; $i1 < $max_t ; $i1++) { if ($rieki[$k1][$i1] > $max) $max = $rieki[$k1][$i1]; } printf("最大利益(最大効用) %d\n", $max); ?>
N W w1 v1 // 1 番目の品物の重さとそれを入れた場合の効用 w2 v2 // 2 番目の品物の重さとそれを入れた場合の効用 ・・・ wN vN
4 6 1 2 3 5 3 4 3 3
<?php /***************************************/ /* 動的計画法(0-1ナップザック問題) */ /* ー品物毎のデータを出力したい場合ー */ /* coded by Y.Suganuma */ /***************************************/ // データの入力と領域の確保 fscanf(STDIN, "%d %d", $N, $W); // 品物の数,重さの上限 $w = array($N); // 各品物の重さ $v = array($N); // 各品物の効用 for ($i1 = 0; $i1 < $N; $i1++) fscanf(STDIN, "%d %d", $w[$i1], $v[$i1]); // 動的計画法 // 初期設定(1段目) $prev = array($N); // 前段までの品物の重さ $dp = array($N); // ナップザック内の品物の重さ for ($i1 = 0; $i1 < $N; $i1++) { $prev[$i1] = array($W+1); $dp[$i1] = array($W+1); } for ($i1 = 0; $i1 <= $W; $i1++) $dp[0][$i1] = -1; if ($w[0] <= $W) $dp[0][$w[0]] = $v[0]; for ($i1 = 0; $i1 <= $W; $i1++) $prev[0][$i1] = -1; // 2段目以降 for ($i1 = 1; $i1 < $N; $i1++) { for ($wt = 0; $wt <= $W; $wt++) { $dp[$i1][$wt] = $dp[$i1-1][$wt]; $prev[$i1][$wt] = $prev[$i1-1][$wt]; } // 最初の品物である場合 if ($w[$i1] <= $W && $dp[$i1][$w[$i1]] < $v[$i1]) { $dp[$i1][$w[$i1]] = $v[$i1]; $prev[$i1][$w[$i1]] = 0; } // 過去に品物が入っている場合 for ($wt = 1; $wt <= $W; $wt++) { if ($dp[$i1-1][$wt] > 0 && $wt+$w[$i1] <= $W) { if ($dp[$i1-1][$wt]+$v[$i1] > $dp[$i1][$wt+$w[$i1]]) { $dp[$i1][$wt+$w[$i1]] = $dp[$i1-1][$wt] + $v[$i1]; $prev[$i1][$wt+$w[$i1]] = $wt; } } } } // 結果の出力 $k = -1; $ans = -1; for ($i1 = 0; $i1 <= $W; $i1++) { if ($dp[$N-1][$i1] > $ans) { $ans = $dp[$N-1][$i1]; $k = $i1; } } printf("最大効用 %d\n", $ans); for ($i1 = $N-1; $i1 > 0; $i1--) { $k1 = 0; if ($dp[$i1][$k] != $dp[$i1-1][$k]) { $k1 = $k - $prev[$i1][$k]; $k = $prev[$i1][$k]; } $vv = ($k1 <= 0) ? 0 : $v[$i1]; printf(" 品物 %d 重さ %d 効用 %d\n", $i1+1, $k1, $vv); } $vv = ($k <= 0) ? 0 : $v[0]; printf(" 品物 1 重さ %d 効用 %d\n", $k, $vv); ?>
<?php /*****************************************/ /* 動的計画法(0-1ナップザック問題) */ /* ー品物毎のデータを必要としない場合ー */ /* coded by Y.Suganuma */ /*****************************************/ // データの入力と領域の確保 fscanf(STDIN, "%d %d", $N, $W); // 品物の数,重さの上限 $w = array($N); // 各品物の重さ $v = array($N); // 各品物の効用 for ($i1 = 0; $i1 < $N; $i1++) fscanf(STDIN, "%d %d", $w[$i1], $v[$i1]); // 動的計画法 // 初期設定(1段目) $dp = array(2); // ナップザック内の品物の重さ for ($i1 = 0; $i1 < 2; $i1++) $dp[$i1] = array($W+1); for ($i1 = 0; $i1 <= $W; $i1++) $dp[0][$i1] = -1; if ($w[0] <= $W) $dp[0][$w[0]] = $v[0]; $k1 = 0; $k2 = 1; // 2段目以降 for ($i1 = 1; $i1 < $N; $i1++) { for ($wt = 0; $wt <= $W; $wt++) $dp[$k2][$wt] = $dp[$k1][$wt]; // 最初の品物である場合 if ($w[$i1] <= $W && $dp[$k2][$w[$i1]] < $v[$i1]) $dp[$k2][$w[$i1]] = $v[$i1]; // 過去に品物が入っている場合 for ($wt = 1; $wt <= $W; $wt++) { if ($dp[$k1][$wt] > 0 && $wt+$w[$i1] <= $W) { if ($dp[$k1][$wt]+$v[$i1] > $dp[$k2][$wt+$w[$i1]]) $dp[$k2][$wt+$w[$i1]] = $dp[$k1][$wt] + $v[$i1]; } } $k1++; $k1 %= 2; $k2++; $k2 %= 2; } $ans = 0; for ($i1 = 0; $i1 <= $W; $i1++) { if ($dp[$k1][$i1] > $ans) $ans = $dp[$k1][$i1]; } printf("最大効用 %d\n", $ans); ?>
N M // ノードの数,接続データの数(接続データが無いノード間は移動できない) ni nj rij // ノード ni と ノード nj 間の距離は rij ・・・
7 10 0 1 2 0 2 5 1 2 4 1 3 6 1 4 10 2 3 2 3 5 1 4 5 3 4 6 5 5 6 9
<?php /*******************************************/ /* 動的計画法(グラフにおける最短距離問題)*/ /* ー経路を出力したい場合ー */ /* coded by Y.Suganuma */ /*******************************************/ // データの入力と領域の確保 fscanf(STDIN, "%d %d", $N, $M); // ノードの数,接続状況データ数 $r = array($N); // ノード間の距離 for ($i1 = 0; $i1 < $N; $i1++) { $r[$i1] = array($N); for ($i2 = 0; $i2 < $N; $i2++) $r[$i1][$i2] = 0; } for ($i1 = 0; $i1 < $M; $i1++) { $str = trim(fgets(STDIN)); $k1 = strtok($str, " "); $k2 = strtok(" "); $r[$k1][$k2] = strtok(" "); } for ($i1 = 0; $i1 < $N-1; $i1++) { for ( $i2 = $i1+1; $i2 < $N; $i2++) $r[$i2][$i1] = $r[$i1][$i2]; } // 動的計画法 // 初期設定(1段目) $prev = array($N); // 前のノード $dp = array($N); // ノードへ達するまでの距離 for ($i1 = 0; $i1 < $N; $i1++) { $prev[$i1] = array($N); $dp[$i1] = array($N); for ($i2 = 0; $i2 < $N; $i2++) { $prev[$i1][$i2] = -1; $dp[$i1][$i2] = -1; } } $dp[0][0] = 0; // 2段目以降 $n = 0; $sw = 1; while($sw > 0) { $sw = 0; for ($i1 = 0; $i1 < $N; $i1++) { $dp[$n+1][$i1] = $dp[$n][$i1]; $prev[$n+1][$i1] = $prev[$n][$i1]; } for ($i1 = 0; $i1 < $N; $i1++) { for ($i2 = 0; $i2 < $N; $i2++) { if ($dp[$n][$i1] >= 0 && $r[$i1][$i2] > 0) { if ($dp[$n+1][$i2] < 0 || ($dp[$n][$i1]+$r[$i1][$i2] < $dp[$n+1][$i2])) { $dp[$n+1][$i2] = $dp[$n][$i1] + $r[$i1][$i2]; $prev[$n+1][$i2] = $i1; $sw = 1; } } } } if ($sw > 0) $n++; } // 結果の出力 printf("最短距離 %d\n", $dp[$n][$N-1]); $k = $N - 1; printf(" ノード番号 %d\n", $k); while ($n > 0) { printf(" ノード番号 %d\n", $prev[$n][$k]); $k = $prev[$n][$k]; $n--; } ?>
<?php /*******************************************/ /* 動的計画法(グラフにおける最短距離問題)*/ /* ー経路を出力する必要が無い場合ー */ /* coded by Y.Suganuma */ /*******************************************/ // データの入力と領域の確保 fscanf(STDIN, "%d %d", $N, $M); // ノードの数,接続状況データ数 $r = array($N); // ノード間の距離 for ($i1 = 0; $i1 < $N; $i1++) { $r[$i1] = array($N); for ($i2 = 0; $i2 < $N; $i2++) $r[$i1][$i2] = 0; } for ($i1 = 0; $i1 < $M; $i1++) { $str = trim(fgets(STDIN)); $k1 = strtok($str, " "); $k2 = strtok(" "); $r[$k1][$k2] = strtok(" "); } for ($i1 = 0; $i1 < $N-1; $i1++) { for ( $i2 = $i1+1; $i2 < $N; $i2++) $r[$i2][$i1] = $r[$i1][$i2]; } // 動的計画法 // 初期設定(1段目) $dp = array(2); // ノードへ達するまでの距離 for ($i1 = 0; $i1 < 2; $i1++) { $dp[$i1] = array($N); for ($i2 = 0; $i2 < $N; $i2++) $dp[$i1][$i2] = -1; } $dp[0][0] = 0; // 2段目以降 $sw = 1; $k1 = 0; $k2 = 1; while($sw > 0) { $sw = 0; for ($i1 = 0; $i1 < $N; $i1++) $dp[$k2][$i1] = $dp[$k1][$i1]; for ($i1 = 0; $i1 < $N; $i1++) { for ($i2 = 0; $i2 < $N; $i2++) { if ($dp[$k1][$i1] >= 0 && $r[$i1][$i2] > 0) { if ($dp[$k2][$i2] < 0 || ($dp[$k1][$i1]+$r[$i1][$i2] < $dp[$k2][$i2])) { $dp[$k2][$i2] = $dp[$k1][$i1] + $r[$i1][$i2]; $sw = 1; } } } } if ($sw > 0) { $k1++; $k1 %= 2; $k2++; $k2 %= 2; } } // 結果の出力 printf("最短距離 %d\n", $dp[$k1][$N-1]); ?>