题解
统计平方和三元组的数目
暴力枚举即可。
Code Q1
class Solution {
public:
int countTriples(int n) {
int res = 0;
for(int a = 1; a <= n; a++ ) {
for(int b = 1; b <= n; b++) {
for(int c = 1; c <= n; c++) {
if (a * a + b * b == c * c)
res ++;
}
}
}
return res;
}
};
迷宫中离入口最近的出口
一道BFS模板题。考试的时候忘记判重卡了好久…
Code Q2
class Solution {
public:
int nearestExit(vector<vector<char>>& maze, vector<int>& e) {
typedef pair<int, int> PII;
int n = maze.size(), m = maze[0].size();
vector<vector<int>> dist(n, vector<int>(m, 1e8));
vector<vector<bool>> st(n, vector<bool>(m, false));
queue<PII> q;
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
q.push({e[0], e[1]});
dist[e[0]][e[1]] = 0;
while (q.size()) {
auto t = q.front();
q.pop();
int x = t.first, y = t.second;
st[x][y] = true;
for (int i = 0 ; i < 4; i++) {
int a = x + dx[i], b = y + dy[i];
if (a < n && a >= 0 && b < m && b >= 0 && maze[a][b] == '.' && dist[a][b] > dist[x][y] + 1) {
dist[a][b] = dist[x][y] + 1;
if (a == 0 || a == n - 1 || b == 0 || b == m - 1) return dist[a][b];
if (!st[a][b]) {
q.push({a, b});
}
}
}
}
return -1;
}
};
求和游戏
分类讨论左右半边的和与问号数量的关系。
- 如果左边和 > 右边 并且左边的问号比右边多。Alice只要采取和Bob对称取值的策略可以获胜,反之同理;
- 如果左边和 > 右边但是左边的问号比右边少。站在Bob的视角,为了达到平衡,Bob一开始只能和Alice对称取,直到一边的问号全部填完。剩下的问题变成:有$x$个问号,两人轮流填数,总和等于某数则Bob赢,否则Alice赢。(1)当$x$为奇数时,Alice必胜,因为最后一次填数是Alice,他无论如何都可以破坏平衡性。(2)当$x$为偶数时,我们可以两两分组,即每一次Alice+Bob填数视为一组。如果总和是9的倍数,假设Alice填的数是$a$,那么Bob总可以找到一个$9 - a$,使得剩下的局面又是Bob的必胜态(即总和为9的倍数),所以Bob必胜,反之,Alcie必胜。
Code Q3
class Solution {
public:
bool sumGame(string num) {
int n = num.size();
int sum1 = 0, sum2 = 0;
int cnt1 = 0, cnt2 = 0;
for(int i = 0; i < n; i++) {
if (i < n / 2) {
if (num[i] == '?') cnt1 ++;
else sum1 += num[i] - '0';
} else {
if (num[i] == '?') cnt2 ++;
else sum2 += num[i] - '0';
}
}
if (cnt1 > cnt2 && sum1 > sum2) return true;
if (cnt1 < cnt2 && sum1 < sum2) return true;
int cnt = abs(cnt1 - cnt2);
int sum = abs(sum1 - sum2);
if (cnt == 0) return sum != 0;
if (cnt % 2) return true;
if ((cnt / 2) * 9 == sum) return false;
return true;
}
};
规定时间内到达终点的最小花费
如果不考虑时间,本题是一个正边权的最短路问题,利用dijkstra或者SPFA等最短路算法可以解决。而如果加上时间,可以将原图的每一个点增加一个维度(拆点)。不妨记$ (t,u)$为点 $u$ 为在 $t$时刻的状态,每条有向边记为$((t,u),(t+w,v))$,表示点$u$到点$v$经过了$w$时间。
设$f(t, u)$表示从$(0,0)$到$(t,u)$的最少费用,初始状态$f(0,0) = passfee(0)$,其余设为无穷大。转移方程$f(t,v)=min(f(t,v),f(t−w,u)+passfee(v))$。最终答案为 $min(f(t,n−1)) $。
本题在实现时有一个技巧,注意到当$t_1 < t_2$时,一定是用$f_1$的状态去更新$f_2$,因此我们可以先枚举时间维度,然后再枚举所有边即可(边的枚举顺序不影响结果)。这种方法的好处是不需要单独建图。
Code Q4
class Solution {
public:
int minCost(int m, vector<vector<int>>& edges, vector<int>& pf) {
const int INF = 1e8;
int n = pf.size();
vector<vector<int>> f(n, vector<int>(m + 1, INF));
f[0][0] = pf[0];
for (int i = 1; i <= m; i++) {
for (const auto& e : edges) {
int x = e[0], y = e[1], cost = e[2];
if (i < cost) continue;
f[x][i] = min(f[x][i], f[y][i - cost] + pf[x]);
f[y][i] = min(f[y][i], f[x][i - cost] + pf[y]);
}
}
int ans = INF;
for (int i = 1; i <= m; i++)
ans = min(ans, f[n - 1][i]);
return ans == INF ? -1 : ans;
}
};
- Post link: https://scnujackychen.github.io/2021/07/18/LC-biweekly-contest-56/
- Copyright Notice: All articles in this blog are licensed under unless otherwise stated.
若没有本文 Issue,您可以使用 Comment 模版新建。
GitHub IssuesGitHub Discussions