算法竞赛>力扣>双周赛 | biweekly-contest-160
3602. 十六进制和三十六进制转化
解题思路
转换、拼接。
代码实现
string concatHex36(int n) {
// 数字转字符
auto c = [&](int x) {
if (x < 10)return '0' + x;
return 'A' + (x - 10);
};
// 将x转为p进制
auto sv = [&](int x, int p) {
string s;
while (x) s.push_back(c(x % p)), x /= p;
reverse(s.begin(), s.end());
return s;
};
// 拼接
return sv(n * n, 16) + sv(n * n * n, 36);
}
时间复杂度 \(O(\log n)\),空间复杂度 \(O(\log n)\)。
3603. 交替方向的最小路径代价 II
解题思路
进入该单元格需要付出成本 \((i + 1) * (j + 1)\)。
只有奇数秒才能进入下一个单元格,当进入到单元格 \((i, j)\) 后,必为偶数秒,必须等待,等到下一秒才能继续前进。
综上,对于单元格 \((i, j)\),需要付出的成本为 \((i + 1) * (j + 1) + waitCost[i][j]\)。
特别的,对于起点和终点,无需等待。
代码实现
反向动态记忆化搜索
后面的由前面的推出。
long long minCost(int m, int n, vector<vector<int>>& waitCost) {
typedef long long ll;
vector dp(m, vector<ll>(n, -1));
function<ll(int, int)> dfs = [&](int i, int j) -> long long {
if (i < 0 || j < 0) return LLONG_MAX;
// 起点只有进入成本
if (i == 0 && j == 0) return 1;
ll& v = dp[i][j];
if (v != -1) return v;
// 当前单元格的成本+前序单元格的成本
return v = min(dfs(i, j - 1), dfs(i - 1, j)) + waitCost[i][j] + (i + 1) * (j + 1);
};
// 终点只有进入成本
return dfs(m - 1, n - 1) - waitCost[m - 1][n - 1];
}
时间复杂度 \(O(mn)\),空间复杂度 \(O(mn)\)。
正向记忆化搜索
前面的由后面的推出。
long long minCost_2(int m, int n, vector<vector<int>>& waitCost) {
typedef long long ll;
vector dp(m, vector<ll>(n, -1));
function<ll(int, int)> dfs = [&](int i, int j) {
if (i >= m || j >= n)return LLONG_MAX;
ll& v = dp[i][j];
if (v != -1)return v;
v = (i + 1) * (j + 1) + waitCost[i][j];
// 终点
if (i == m - 1 && j == n - 1)return v;
return v += min(dfs(i + 1, j), dfs(i, j + 1));
};
// 起点和终点无需等待
return dfs(0, 0) - waitCost[0][0] - waitCost[m - 1][n - 1];
}
时间复杂度 \(O(mn)\),空间复杂度 \(O(mn)\)。
递推
由反向动态记忆化搜索翻译得到。
long long minCost_3(int m, int n, vector<vector<int>>& waitCost) {
typedef long long ll;
vector dp(m + 1, vector<ll>(n + 1, LLONG_MAX));
// 边界值
dp[0][1] = dp[1][0] = -waitCost[0][0];
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++)
// 从上面来或者从左边来的成本+当前方格的成本
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + i * j + waitCost[i - 1][j - 1];
return dp[m][n] - waitCost[m - 1][n - 1];
}
时间复杂度 \(O(mn)\),空间复杂度 \(O(mn)\)。
3604. 有向图中到达终点的最少时间
解题思路
节点的到达时间由前序节点的到达时间决定,只需要从前往后遍历节点即可。
具体该按何种顺序遍历节点呢?每次可拓展到达时间最早的节点,即 Djstra 算法。
代码实现
int minTime(int n, vector<vector<int>>& edges) {
vector<vector<tuple<int, int, int>>> es(n);
vector<int> d(n,INT_MAX);
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> q;
d[0] = 0;
// 邻接矩阵
for (auto& v : edges)
es[v[0]].emplace_back(v[1], v[2], v[3]);
q.emplace(0, 0);
while (!q.empty()) {
const auto [dx,x] = q.top();
q.pop();
// 当前用时大于最短用时
if (dx > d[x])continue;
// 终点
if (x == n - 1) return dx;
// 前进
for (auto& [y, s, e] : es[x]) {
// 超时导致边不可用
if (d[x] > e)continue;
// 当前最早完成时间
int t = max(d[x], s) + 1;
// 全局最早完成时间
if (d[y] > t) d[y] = t, q.emplace(t, y);
}
}
return -1;
}
时间复杂度 \(O(n+m\log m)\),空间复杂度 \(O(n + m)\)。

算法竞赛>力扣>双周赛:十六进制和三十六进制转化、交替方向的最小路径代价II、有向图中到达终点的最少时间,涉及数学、动态规划、最短路。
浙公网安备 33010602011771号