トピックリンク:リトゥオ
n
各頂点に整数値を持つ凸多角形があります 。 が番目の頂点の値で ある values
整数 の配列が与えられた場合 (つまり、時計回りの順序で )。values[i]
i
多角形が 三角形 に 分割されているとn - 2
します 。各三角形について、その三角形の値は頂点ラベルの積であり、三角形分割スコアは n - 2
三角形分割後のすべての三角形の値の合計です。
三角測量後の多角形の最低スコアを返します 。
例 1:
入力:値 = [1,2,3] 出力: 6 説明:多角形は、一意の三角形のスコア 6 で三角形化されています。
例 2:
入力:値 = [3,7,4,5] 出力: 144 説明:可能なスコアを持つ 2 つの三角形分割があります: 3*7*5 + 4*5*7 = 245、または 3*4*5 + 3 *4*7 = 144。最低スコアは 144 です。
例 3:
入力:値 = [1,3,1,4,1,5] 出力: 13 説明:最小スコアの三角形分割のスコア ケースは 1*1*3 + 1*1*4 + 1*1*5 です。 + 1 *1*1 = 13.
ヒント:
n == values.length
3 <= n <= 50
1 <= values[i] <= 100
公式説明メモ
class Solution {
public:
int minScoreTriangulation(vector<int>& values) {
// 记忆化存储已经计算过的子问题的解
unordered_map<int, int> memo;
int n = values.size();
// 定义 dp 函数
function<int(int, int)> dp = [&](int i, int j) -> int {
// 三角形的边长小于 3,不需要划分,返回 0
if (i + 2 > j) {
return 0;
}
// 三角形的边长等于 3,只有一个三角形,返回这个三角形的分数
if (i + 2 == j) {
return values[i] * values[i + 1] * values[j];
}
// 计算 memo 的 key
int key = i * n + j;
// 如果当前子问题的解没有计算过
if (!memo.count(key)) {
int minScore = INT_MAX;
// 枚举划分位置 k,计算每种划分方式的分数,取最小值
for (int k = i + 1; k < j; k++) {
minScore = min(minScore, values[i] * values[k] * values[j] + dp(i, k) + dp(k, j));
}
// 存储当前子问题的解
memo[key] = minScore;
}
// 返回当前子问题的解
return memo[key];
};
// 返回最终问题的解
return dp(0, n - 1);
}
};
ChatGPT質問解説アノテーション版
class Solution {
public:
int minScoreTriangulation(vector<int>& values) {
int n = values.size();
// dp[i][j]表示从第i个点到第j个点所需的最小分数
vector<vector<int>> dp(n, vector<int>(n));
// 遍历区间长度
for (int len = 3; len <= n; len++) {
// 遍历区间起点
for (int i = 0; i + len - 1 < n; i++) {
// 区间终点
int j = i + len - 1;
// 初始化dp[i][j]
dp[i][j] = INT_MAX;
// 遍历区间中间点
for (int k = i + 1; k < j; k++) {
// 求解dp[i][j]
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j] + values[i] * values[j] * values[k]);
}
}
}
// dp[0][n-1]即为答案
return dp[0][n - 1];
}
};
unordered_map<int, int>
unordered_map<int, int> は C++ STL (標準テンプレート ライブラリ) の連想コンテナーで、キーと値のペアのセットを一意の値にマップできます。この特定のコードでは、 unordered_map<int, int> memo; を使用して計算結果を保存し、後で使用できるようにして、計算の繰り返しを回避し、コードの効率を向上させています。
vector<int>&
vector<int>& は参照を表し、型 vector<int> の変数を関数のパラメーターとして受け取るために使用されるため、新しいコピーを作成する代わりに変数を関数で直接変更できます。参照を使用すると、関数内で大量のデータをコピーすることを回避できるため、プログラムの効率が向上します。同時に、参照を使用して、関数の戻り値を呼び出し元に渡すこともできます。
function<int(int, int)> dp = [&](int i, int j) -> int
このコードはラムダ式を使用しており、その構造は次のとおりです。
[&](int i, int j) -> int {
// 函数体
return 0;
}
このうち&
、 はラムダ式が使用されるスコープ内の変数を表し、int i, int j
パラメータ リストを表し、-> int
戻り値の型を表しますint
。これは、int
2 つの整数パラメーターの戻り値を持つラムダ関数を定義します。
この問題では、このラムダ関数を動的計画法関数として使用して、i 番目のポイントから j 番目のポイントまでに必要な最小スコアを計算します。