
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
/***************************************************/
/* 動的計画法:資源配分問題(0-1 ナップザック問題)*/
/* ー投資先(品物)毎のデータを出力したい場合ー */
/* coded by Y.Suganuma */
/***************************************************/
import java.io.*;
import java.util.*;
public class Test {
public static void main(String args[]) throws IOException
{
// データの入力と領域の確保
Scanner sc = new Scanner(System.in);
int n_toshi = sc.nextInt(); // 投資先数(品物数)
int max_t = sc.nextInt(); // 最大投資額(最大重量)
max_t++; // 投資を行わない(品物を入れない)場合を含めるため
int table[][] = new int [n_toshi][max_t]; // 投資額と利益(重さと効用)
int rieki[][] = new int [n_toshi][max_t]; // 投資した際の利益(品物を入れた際の効用)
int prev[][] = new int [n_toshi][max_t]; // 前段までの投資額(前段までの重さ)
for (int i1 = 0; i1 < n_toshi; i1++) {
table[i1][0] = 0;
for (int i2 = 1; i2 < max_t; i2++)
table[i1][i2] = sc.nextInt();
}
// 動的計画法
// 初期設定(1段目)
for (int i1 = 0; i1 < max_t; i1++) {
rieki[0][i1] = table[0][i1];
prev[0][i1] = -1;
}
// 2段目以降
for (int i1 = 1; i1 < n_toshi; i1++) {
for (int i2 = 0; i2 < max_t; i2++) {
rieki[i1][i2] = rieki[i1-1][i2];
prev[i1][i2] = prev[i1-1][i2];
}
for (int i2 = 0; i2 < max_t; i2++) {
for (int 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;
}
}
}
}
// 結果の出力
int k = -1, max = -1;
for (int i1 = 0; i1 < max_t ; i1++) {
if (rieki[n_toshi-1][i1] > max) {
max = rieki[n_toshi-1][i1];
k = i1;
}
}
System.out.printf("最大利益(最大効用) %d\n", max);
for (int i1 = n_toshi-1; i1 > 0; i1--) {
int k1 = 0;
if (rieki[i1][k] != rieki[i1-1][k]) {
k1 = k - prev[i1][k];
k = prev[i1][k];
}
System.out.printf(" 投資先(品物) %d 投資単位(重さ) %d 利益(効用) %d\n",
i1+1, k1, table[i1][k1]);
}
System.out.printf(" 投資先(品物) 1 投資単位(重さ) %d 利益(効用) %d\n",
k, table[0][k]);
}
}
/***************************************************/
/* 動的計画法:資源配分問題(0-1 ナップザック問題)*/
/* ー投資先(品物)毎のデータを必要としない場合ー */
/* coded by Y.Suganuma */
/***************************************************/
import java.io.*;
import java.util.*;
public class Test {
public static void main(String args[]) throws IOException
{
// データの入力と領域の確保
Scanner sc = new Scanner(System.in);
int n_toshi = sc.nextInt(); // 投資先数(品物数)
int max_t = sc.nextInt(); // 最大投資額(最大重量)
max_t++; // 投資を行わない(品物を入れない)場合を含めるため
int table[][] = new int [n_toshi][max_t]; // 投資額と利益(重さと効用)
int rieki[][] = new int [2][max_t]; // 投資した際の利益(品物を入れた際の効用)
for (int i1 = 0; i1 < n_toshi; i1++) {
table[i1][0] = 0;
for (int i2 = 1; i2 < max_t; i2++)
table[i1][i2] = sc.nextInt();
}
// 動的計画法
// 初期設定(1段目)
int k1 = 0, k2 = 1;
for (int i1 = 0; i1 < max_t; i1++)
rieki[0][i1] = table[0][i1];
// 2段目以降
for (int i1 = 1; i1 < n_toshi; i1++) {
for (int i2 = 0; i2 < max_t; i2++)
rieki[k2][i2] = rieki[k1][i2];
for (int i2 = 0; i2 < max_t; i2++) {
for (int 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;
}
// 結果の出力
int max = -1;
for (int i1 = 0; i1 < max_t ; i1++) {
if (rieki[k1][i1] > max)
max = rieki[k1][i1];
}
System.out.printf("最大利益(最大効用) %d\n", max);
}
}
N W w1 v1 // 1 番目の品物の重さとそれを入れた場合の効用 w2 v2 // 2 番目の品物の重さとそれを入れた場合の効用 ・・・ wN vN
4 6 1 2 3 5 3 4 3 3
/***************************************/
/* 動的計画法(0-1ナップザック問題) */
/* ー品物毎のデータを出力したい場合ー */
/* coded by Y.Suganuma */
/***************************************/
import java.io.*;
import java.util.*;
public class Test {
public static void main(String args[]) throws IOException
{
// データの入力と領域の確保
Scanner sc = new Scanner(System.in);
int N = sc.nextInt(); // 品物の数
int W = sc.nextInt(); // 重さの上限
int w[] = new int [N]; // 各品物の重さ
int v[] = new int [N]; // 各品物の効用
for (int i1 = 0; i1 < N; i1++) {
w[i1] = sc.nextInt();
v[i1] = sc.nextInt();
}
// 動的計画法
// 初期設定(1段目)
int prev[][] = new int [N][W+1]; // 前段までの品物の重さ
int dp[][] = new int [N][W+1]; // ナップザック内の品物の重さ
for (int i1 = 0; i1 <= W; i1++)
dp[0][i1] = -1;
if (w[0] <= W)
dp[0][w[0]] = v[0];
for (int i1 = 0; i1 <= W; i1++)
prev[0][i1] = -1;
// 2段目以降
for (int i1 = 1; i1 < N; i1++) {
for (int 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 (int 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;
}
}
}
}
// 結果の出力
int k = -1, ans = -1;
for (int i1 = 0; i1 <= W; i1++) {
if (dp[N-1][i1] > ans) {
ans = dp[N-1][i1];
k = i1;
}
}
System.out.printf("最大効用 %d\n", ans);
for (int i1 = N-1; i1 > 0; i1--) {
int k1 = 0;
if (dp[i1][k] != dp[i1-1][k]) {
k1 = k - prev[i1][k];
k = prev[i1][k];
}
int vv = (k1 <= 0) ? 0 : v[i1];
System.out.printf(" 品物 %d 重さ %d 効用 %d\n", i1+1, k1, vv);
}
int vv = (k <= 0) ? 0 : v[0];
System.out.printf(" 品物 1 重さ %d 効用 %d\n", k, vv);
}
}
/*****************************************/
/* 動的計画法(0-1ナップザック問題) */
/* ー品物毎のデータを必要としない場合ー */
/* coded by Y.Suganuma */
/*****************************************/
import java.io.*;
import java.util.*;
public class Test {
public static void main(String args[]) throws IOException
{
// データの入力と領域の確保
Scanner sc = new Scanner(System.in);
int N = sc.nextInt(); // 品物の数
int W = sc.nextInt(); // 重さの上限
int w[] = new int [N]; // 各品物の重さ
int v[] = new int [N]; // 各品物の効用
for (int i1 = 0; i1 < N; i1++) {
w[i1] = sc.nextInt();
v[i1] = sc.nextInt();
}
// 動的計画法
// 初期設定(1段目)
int dp[][] = new int [2][W+1]; // ナップザック内の品物の重さ
for (int i1 = 0; i1 <= W; i1++)
dp[0][i1] = -1;
if (w[0] <= W)
dp[0][w[0]] = v[0];
int k1 = 0, k2 = 1;
// 2段目以降
for (int i1 = 1; i1 < N; i1++) {
for (int 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 (int 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;
}
// 結果の出力
int ans = 0;
for (int i1 = 0; i1 <= W; i1++) {
if (dp[k1][i1] > ans)
ans = dp[k1][i1];
}
System.out.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
/*******************************************/
/* 動的計画法(グラフにおける最短距離問題)*/
/* ー経路を出力したい場合ー */
/* coded by Y.Suganuma */
/*******************************************/
import java.io.*;
import java.util.*;
public class Test {
public static void main(String args[]) throws IOException
{
// データの入力と領域の確保
Scanner sc = new Scanner(System.in);
int N = sc.nextInt(); // ノードの数
int M = sc.nextInt(); // 接続状況データ数
int r[][] = new int [N][N]; // ノード間の距離
for (int i1 = 0; i1 < N; i1++) {
for (int i2 = 0; i2 < N; i2++)
r[i1][i2] = 0;
}
for (int i1 = 0; i1 < M; i1++) {
int k1 = sc.nextInt();
int k2 = sc.nextInt();
r[k1][k2] = sc.nextInt();
}
for (int i1 = 0; i1 < N-1; i1++) {
for (int i2 = i1+1; i2 < N; i2++)
r[i2][i1] = r[i1][i2];
}
// 動的計画法
// 初期設定(1段目)
int prev[][] = new int [N][N]; // 前のノード
int dp[][] = new int [N][N]; // ノードへ達するまでの距離
for (int i1 = 0; i1 < N; i1++) {
for (int i2 = 0; i2 < N; i2++) {
prev[i1][i2] = -1;
dp[i1][i2] = -1;
}
}
dp[0][0] = 0;
// 2段目以降
int n = 0, sw = 1;
while(sw > 0) {
sw = 0;
for (int i1 = 0; i1 < N; i1++) {
dp[n+1][i1] = dp[n][i1];
prev[n+1][i1] = prev[n][i1];
}
for (int i1 = 0; i1 < N; i1++) {
for (int 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++;
}
// 結果の出力
System.out.printf("最短距離 %d\n", dp[n][N-1]);
int k = N - 1;
System.out.printf(" ノード番号 %d\n", k);
while (n > 0) {
System.out.printf(" ノード番号 %d\n", prev[n][k]);
k = prev[n][k];
n--;
}
}
}
/*******************************************/
/* 動的計画法(グラフにおける最短距離問題)*/
/* ー経路を出力する必要が無い場合ー */
/* coded by Y.Suganuma */
/*******************************************/
import java.io.*;
import java.util.*;
public class Test {
public static void main(String args[]) throws IOException
{
// データの入力と領域の確保
Scanner sc = new Scanner(System.in);
int N = sc.nextInt(); // ノードの数
int M = sc.nextInt(); // 接続状況データ数
int r[][] = new int [N][N]; // ノード間の距離
for (int i1 = 0; i1 < N; i1++) {
for (int i2 = 0; i2 < N; i2++)
r[i1][i2] = 0;
}
for (int i1 = 0; i1 < M; i1++) {
int k1 = sc.nextInt();
int k2 = sc.nextInt();
r[k1][k2] = sc.nextInt();
}
for (int i1 = 0; i1 < N-1; i1++) {
for (int i2 = i1+1; i2 < N; i2++)
r[i2][i1] = r[i1][i2];
}
// 動的計画法
// 初期設定(1段目)
int dp[][] = new int [2][N]; // ノードへ達するまでの距離
for (int i1 = 0; i1 < 2; i1++) {
for (int i2 = 0; i2 < N; i2++)
dp[i1][i2] = -1;
}
dp[0][0] = 0;
// 2段目以降
int sw = 1, k1 = 0, k2 = 1;
while(sw > 0) {
sw = 0;
for (int i1 = 0; i1 < N; i1++)
dp[k2][i1] = dp[k1][i1];
for (int i1 = 0; i1 < N; i1++) {
for (int 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;
}
}
// 結果の出力
System.out.printf("最短距離 %d\n", dp[k1][N-1]);
}
}