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]);
?>