算法板子(个人向)
基础算法
二分
板子1
搜索区间左闭右闭
n = len(nums)
l, r = 0, n - 1
while l <= r:
mid = l + r >> 1
if nums[mid] == target: return mid
elif nums[mid] > target: r = mid - 1
else: l = mid + 1
return -1
板子2.1
n = len(nums)
l, r = 0, n - 1
while l < r:
mid = l + r >> 1
if check(mid): r = mid
else: l = mid + 1
return r
板子2.2
n = len(nums)
l, r = 0, n - 1
while l < r:
mid = l + r + 1 >> 1
if check(mid): l = mid
else: r = mid - 1
return r
数据结构
单调栈
-
一般适用于数组中求下一个更大或者更小元素值的题型
-
求下一个更大值那就维护单调递减栈,否则就维护单调递增栈,至于是否需要严格单调,按照题目意思进行相应调整即可。
-
单调栈中存的内容一般是下标或者值
下一个更大情况(单调递减栈)
n = len(nums)
stack = []
for i in range(n):
while stack and nums[i] > nums[stack[-1]]:
stack.pop()
if stack:
# 这里填写相应逻辑
stack.append(i)
一遍遍历求左右两边下一个更小数
n = len(nums)
left, right = [-1] * n, [-1] * n
stack = []
for i in range(n):
while stack and nums[i] <= nums[stack[-1]]:
right[stack.pop()] = i
if stack:
left[i] = stack[-1]
else:
left[i] = -1
图论
链式前向星
邻接表的建图方式
记得初始化h数组为-1
int h[N], e[N], ne[N], idx, w[N];
inline void add(int a, int b, int c)
{
w[idx] = c, e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
最短路
朴素版迪杰斯特拉算法
int n, m;
int g[N][N], dist[N];
bool st[N];
void dijkstra()
{
dist[1] = 0;
for (int i = 1; i <= n; ++i)
{
int t = -1;
for (int j = 1; j <= n; ++j)
if (!st[j] && (t == -1 || dist[j] < dist[t]))
t = j;
st[t] = true;
for (int j = 1; j <= n; ++j)
{
if (dist[j] > dist[t] + g[t][j])
dist[j] = dist[t] + g[t][j];
}
}
if (dist[n] == INF) cout << -1 << endl;
else cout << dist[n] << endl;
}
void solve()
{
memset(g, 0x3f, sizeof g);
memset(dist, 0x3f, sizeof dist);
cin >> n >> m;
for (int i = 0; i < m; ++i)
{
int a, b, c; cin >> a >> b >> c;
g[a][b] = min(g[a][b], c);
}
dijkstra();
}
堆优化版的迪杰斯特拉算法
int h[N], e[N], ne[N], idx, w[N];
int dist[N];
bool st[N];
int n, m;
inline void add(int a, int b, int c)
{
w[idx] = c, e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dijkstra()
{
dist[1] = 0;
priority_queue<pii, vector<pii>, greater<pii>> q;
q.push({0, 1}); // dist, node
while (q.size())
{
auto t = q.top();
q.pop();
int ver = t.yy, d = t.xx;
if (st[ver]) continue;
st[ver] = true;
for (int i = h[ver]; ~i; i = ne[i])
{
int j = e[i];
if (dist[j] > d + w[i])
{
dist[j] = d + w[i];
q.push({dist[j], j});
}
}
}
if (dist[n] == INF) cout << -1 << endl;
else cout << dist[n] << endl;
}
void solve()
{
memset(dist, 0x3f, sizeof dist);
memset(h, -1, sizeof h);
cin >> n >> m;
for (int i = 0; i < m; ++i)
{
int a, b, c; cin >> a >> b >> c;
add(a, b, c);
}
dijkstra();
}
bellman-ford算法(存在负权边且有边数限制)
const int INF = 0x3f3f3f3f, N = 1e4 + 10;
int dist[N], backup[N];
int n, m, k;
struct Edge
{
int a, b, w;
}edges[N];
void bellman_ford()
{
dist[1] = 0;
for (int i = 0; i < k; ++i)
{
// 每次循环前备份
memcpy(backup, dist, sizeof dist);
for (int j = 0; j < m; ++j)
{
int st = edges[j].a, ed = edges[j].b, w = edges[j].w;
if (dist[ed] > backup[st] + w)
dist[ed] = backup[st] + w;
}
}
if (dist[n] > INF / 2) cout << "impossible" << endl;
else cout << dist[n] << endl;
}
void solve()
{
memset(dist, 0x3f, sizeof dist);
memset(backup, 0x3f, sizeof backup);
cin >> n >> m >> k;
for (int i = 0; i < m; ++i) cin >> edges[i].a >> edges[i].b >> edges[i].w;
bellman_ford();
}
spfa算法(存在负权边)
const int INF = 0x3f3f3f3f, N = 1e5 + 10;
int n, m;
int dist[N];
bool st[N];
int h[N], e[N], ne[N], idx, w[N];
inline void add(int a, int b, int c)
{
w[idx] = c, e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void spfa()
{
queue<int> q;
dist[1] = 0;
st[1] = true;
q.push(1);
while (q.size())
{
auto t = q.front();
q.pop();
st[t] = false;
for (int i = h[t]; ~i; i = ne[i])
{
int j = e[i];
if (dist[j] > dist[t] + w[i])
{
dist[j] = dist[t] + w[i];
if (!st[j])
{
st[j] = true;
q.push(j);
}
}
}
}
if (dist[n] == INF) cout << "impossible" << endl;
else cout << dist[n] << endl;
}
void solve()
{
memset(dist, 0x3f, sizeof dist);
memset(h, -1, sizeof h);
cin >> n >> m;
for (int i = 0; i < m; ++i)
{
int a, b, c; cin >> a >> b >> c;
add(a, b, c);
}
spfa();
}
floyd算法(带保存路径)
const int INF = 0x3f3f3f3f, N = 210;
int dist[N][N], p[N][N]; // p[i][j]代表i-j两点之间最短路径必须经过p[i][j]表示的点
int n, m, t;
void floyd()
{
for (int k = 1; k <= n; ++k)
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
if (dist[i][j] > dist[i][k] + dist[k][j])
{
dist[i][j] = dist[i][k] + dist[k][j];
p[i][j] = k; // i-j之间必须经过k
}
}
string get_path(int u, int v)
{
if (p[u][v] == -1) return to_string(u) + "->"; // base case: 直接相连的情况
int k = p[u][v];
return get_path(u, k) + get_path(k, v); // 返回左右两端u->k以及k->v的路径
}
void solve()
{
cin >> n >> m >> t;
memset(dist, 0x3f, sizeof dist);
memset(p, 0x3f, sizeof p);
for (int i = 1; i <= n; ++i) dist[i][i] = 0; // 处理自环
for (int i = 0; i < m; ++i)
{
int a, b, c;
cin >> a >> b >> c;
dist[a][b] = min(dist[a][b], c); // 处理重边
p[a][b] = -1; // 如果两点之间有一条直接路径,那么意味着无需经过任何点,我们设为-1
}
floyd();
while (t--)
{
int x, y;
cin >> x >> y;
if (dist[x][y] > INF / 2) cout << "impossible" << endl; // 由于循环过程可能存在负权边更新,所以必须要大于inf/2
else
{
cout << dist[x][y] << endl;
string path = get_path(x, y) + to_string(y);
cout << path << endl;
}
}
}

浙公网安备 33010602011771号