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 */ /***************************************************/ #include <stdio.h> int main() { // データの入力と領域の確保 int n_toshi, max_t; // 投資先数(品物数),最大投資額(最大重量) scanf("%d %d", &n_toshi, &max_t); max_t++; // 投資を行わない(品物を入れない)場合を含めるため int **table = new int * [n_toshi]; // 投資額と利益(重さと効用) int **rieki = new int * [n_toshi]; // 投資した際の利益(品物を入れた際の効用) int **prev = new int * [n_toshi]; // 前段までの投資額(前段までの重さ) for (int i1 = 0; i1 < n_toshi; i1++) { table[i1] = new int [max_t]; rieki[i1] = new int [max_t]; prev[i1] = new int [max_t]; } for (int i1 = 0; i1 < n_toshi; i1++) { table[i1][0] = 0; for (int i2 = 1; i2 < max_t; i2++) scanf("%d", &table[i1][i2]); } // 動的計画法 // 初期設定(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; } } 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]; } printf(" 投資先(品物) %d 投資単位(重さ) %d 利益(効用) %d\n", i1+1, k1, table[i1][k1]); } printf(" 投資先(品物) 1 投資単位(重さ) %d 利益(効用) %d\n", k, table[0][k]); return 0; }
/***************************************************/ /* 動的計画法:資源配分問題(0-1 ナップザック問題)*/ /* ー投資先(品物)毎のデータを必要としない場合ー */ /* coded by Y.Suganuma */ /***************************************************/ #include <stdio.h> int main() { // データの入力と領域の確保 int n_toshi, max_t; // 投資先数(品物数),最大投資額(最大重量) scanf("%d %d", &n_toshi, &max_t); max_t++; // 投資を行わない(品物を入れない)場合を含めるため int **table = new int * [n_toshi]; // 投資額と利益(重さと効用) int **rieki = new int * [2]; // 投資した際の利益(品物を入れた際の効用) for (int i1 = 0; i1 < n_toshi; i1++) table[i1] = new int [max_t]; for (int i1 = 0; i1 < 2; i1++) rieki[i1] = new int [max_t]; for (int i1 = 0; i1 < n_toshi; i1++) { table[i1][0] = 0; for (int i2 = 1; i2 < max_t; i2++) scanf("%d", &table[i1][i2]); } // 動的計画法 // 初期設定(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]; } printf("最大利益(最大効用) %d\n", max); return 0; }
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 */ /***************************************/ #include <stdio.h> int main() { // データの入力と領域の確保 int N, W, *w, *v; scanf("%d %d", &N, &W); // 品物の数,重さの上限 w = new int [N]; // 各品物の重さ v = new int [N]; // 各品物の効用 for (int i1 = 0; i1 < N; i1++) scanf("%d %d", &w[i1], &v[i1]); // 動的計画法 // 初期設定(1段目) int **prev = new int * [N]; // 前段までの品物の重さ int **dp = new int *[N]; // ナップザック内の品物の重さ for (int i1 = 0; i1 < N; i1++) { prev[i1] = new int [W+1]; dp[i1] = new int [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; } } 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]; printf(" 品物 %d 重さ %d 効用 %d\n", i1+1, k1, vv); } int vv = (k <= 0) ? 0 : v[0]; printf(" 品物 1 重さ %d 効用 %d\n", k, vv); return 0; }
/*****************************************/ /* 動的計画法(0-1ナップザック問題) */ /* ー品物毎のデータを必要としない場合ー */ /* coded by Y.Suganuma */ /*****************************************/ #include <stdio.h> int main() { // データの入力と領域の確保 int N, W, *w, *v; scanf("%d %d", &N, &W); // 品物の数,重さの上限 w = new int [N]; // 各品物の重さ v = new int [N]; // 各品物の効用 for (int i1 = 0; i1 < N; i1++) scanf("%d %d", &w[i1], &v[i1]); // 動的計画法 // 初期設定(1段目) int **dp = new int *[2]; // ナップザック内の品物の重さ for (int i1 = 0; i1 < 2; i1++) dp[i1] = new int [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]; } printf("最大効用 %d\n", ans); return 0; }
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 */ /*******************************************/ #include <stdio.h> int main() { // データの入力と領域の確保 int N, M; scanf("%d %d", &N, &M); // ノードの数,接続状況データ数 int **r = new int *[N]; // ノード間の距離 for (int i1 = 0; i1 < N; i1++) { r[i1] = new int [N]; for (int i2 = 0; i2 < N; i2++) r[i1][i2] = 0; } for (int i1 = 0; i1 < M; i1++) { int k1, k2; scanf("%d %d", &k1, &k2); scanf("%d", &r[k1][k2]); } 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]; // 前のノード int **dp = new int *[N]; // ノードへ達するまでの距離 for (int i1 = 0; i1 < N; i1++) { prev[i1] = new int [N]; dp[i1] = new int [N]; 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++; } // 結果の出力 printf("最短距離 %d\n", dp[n][N-1]); int k = N - 1; printf(" ノード番号 %d\n", k); while (n > 0) { printf(" ノード番号 %d\n", prev[n][k]); k = prev[n][k]; n--; } return 0; }
/*******************************************/ /* 動的計画法(グラフにおける最短距離問題)*/ /* ー経路を出力する必要が無い場合ー */ /* coded by Y.Suganuma */ /*******************************************/ #include <stdio.h> int main() { // データの入力と領域の確保 int N, M; scanf("%d %d", &N, &M); // ノードの数,接続状況データ数 int **r = new int *[N]; // ノード間の距離 for (int i1 = 0; i1 < N; i1++) { r[i1] = new int [N]; for (int i2 = 0; i2 < N; i2++) r[i1][i2] = 0; } for (int i1 = 0; i1 < M; i1++) { int k1, k2; scanf("%d %d", &k1, &k2); scanf("%d", &r[k1][k2]); } 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]; // ノードへ達するまでの距離 for (int i1 = 0; i1 < 2; i1++) { dp[i1] = new int [N]; 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; } } // 結果の出力 printf("最短距離 %d\n", dp[k1][N-1]); return 0; }