算法板子(个人向)

基础算法

二分

板子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

数据结构

单调栈

  1. 一般适用于数组中求下一个更大或者更小元素值的题型

  2. 求下一个更大值那就维护单调递减栈,否则就维护单调递增栈,至于是否需要严格单调,按照题目意思进行相应调整即可。

  3. 单调栈中存的内容一般是下标或者值

下一个更大情况(单调递减栈)

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;
        }
    }
}
posted @ 2023-02-08 19:21  Pluto_Evans  阅读(55)  评论(0)    收藏  举报