算法模板(4):动态规划(4) 做题积累(2)

这篇具有很好参考价值的文章主要介绍了算法模板(4):动态规划(4) 做题积累(2)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

动态规划

9. 单调队列优化DP

1. 1088. 旅行问题

John 打算驾驶一辆汽车周游一个环形公路。

公路上总共有 n 个车站,每站都有若干升汽油(有的站可能油量为零),每升油可以让汽车行驶一千米。

John 必须从某个车站出发,一直按顺时针(或逆时针)方向走遍所有的车站,并回到起点。

在一开始的时候,汽车内油量为零,John 每到一个车站就把该站所有的油都带上(起点站亦是如此),行驶过程中不能出现没有油的情况。

任务:判断以每个车站为起点能否按条件成功周游一周。

  • 做法:把环形序列扩展一倍成一条链,设距离是 d i d_i di,加油站的油量是 o i o_i oi,打一个 o i − d i o_i - d_i oidi 的前缀和,从第 k k k 个点出发可以到达,等价于 ∀ i ∈ [ k , k + n − 1 ] , s [ i ] − s [ k − 1 ] ≥ 0 \forall i \in [k, k + n - 1],s[i]-s[k - 1] \ge 0 i[k,k+n1],s[i]s[k1]0,即可以找到长度为 n n n 的窗口的最小值,然后减去 s [ k − 1 ] s[k - 1] s[k1] 看看是否大于等于 0.
  • 细节巨多.
#include<bits/stdc++.h>
using namespace std;
const int N = 2000010;
typedef long long ll;
ll o[N], d[N], s[N];
int q[N], n;
int st[N];

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%d%d", &o[i], &d[i]);
    for(int i = 1; i <= n; i++)
    {
        s[i] = s[i + n] = o[i] - d[i];
    }
    for(int i = 1; i <= 2 * n; i++) s[i] += s[i - 1];

    int hh = 0, tt = -1;
    
    //顺时针
    for(int i = 2 * n; i; i--)
    {
        if(q[hh] >= n + i) hh++;
        while(hh <= tt && s[q[hh]] >= s[i]) tt--;
        q[++tt] = i;
        if(i <= n)
        {
            if(s[q[hh]] - s[i - 1] >= 0) st[i] = true;
        }
    }
    
    //逆时针,整个前缀和序列会发生变化
    
    hh = 0, tt = -1;
    d[0] = d[n];
    for(int i = 1; i <= n; i++) s[i] = s[i + n]= o[i] - d[i - 1];
    for(int i = 2 * n; i; i--) s[i] += s[i + 1];
    
    for(int i = 1; i <= 2 * n; i++)
    {
        if(q[hh] <= i - n) hh++;
        while(hh <= tt && s[q[hh]] >= s[i]) tt--;
        q[++tt] = i;
        if(i > n)
        {
            //注意这里是 st[i - n] 
            if(s[q[hh]] - s[i + 1] >= 0) st[i - n] = true;
        }
    }
    
    for(int i = 1; i <= n; i++)
    {
        printf("%s\n", st[i] ? "TAK" : "NIE");
    }
    return 0;
}

2. 1090. 绿色通道

  • 高二数学《绿色通道》总共有 n n n 道题目要抄,编号 1 , 2 , … , n 1,2,…,n 1,2,,n,抄第 i i i 题要花 a i a_i ai 分钟。小 Y 决定只用不超过 t t t 分钟抄这个,因此必然有空着的题。连续空着的题目(称为空题段)越多,老师越生气。小 Y 想让最长的空题段长度尽可能地小,请输出这个最小值.
  • 二分一下,就和 烽火传递 思路一样了.
#include<bits/stdc++.h>
using namespace std;
const int N = 50010;
int q[N], w[N], f[N];
int n, t;

bool check(int m)
{
    int hh = 0, tt = -1;
    q[++tt] = 0;
    for(int i = 1; i <= n; i++)
    {
        if(q[hh] < i - m - 1) hh++;
        f[i] = f[q[hh]] + w[i];
        while(hh <= tt && f[q[tt]] >= f[i]) tt--;
        q[++tt] = i;
    }
    
    for(int i = n - m; i <= n; i++)
    {
        if(f[i] <= t) return true;
    }
    return false;
}

int main()
{
    scanf("%d%d", &n, &t);
    for(int i = 1; i <= n; i++) scanf("%d", &w[i]);
    int l = 0, r = n;
    while(l < r)
    {
        int mid = (l + r) / 2;
        if(check(mid)) r = mid;
        else l = mid + 1;
    }
    printf("%d\n", l);
    return 0;
}

3. 1087. 修剪草坪

FJ 有 N N N 只排成一排的奶牛,编号为 1 1 1 N N N。每只奶牛的效率是不同的,奶牛 i i i 的效率为 E i E_i Ei。编号相邻的奶牛们很熟悉,如果 FJ 安排超过 K K K 只编号连续的奶牛,那么这些奶牛就会罢工去开派对。因此,现在 FJ 需要你的帮助,找到最合理的安排方案并计算 FJ 可以得到的最大效率。注意,方案需满足不能包含超过 K K K 只编号连续的奶牛。

这个题有一个很简单的做法,就是类似于 烽火传递 那个题,不过我们这次是选出来不选的牛,让这些牛的效率之和最小。可以转化为在长度为 K + 1 K+1 K+1 的连续子序列中至少选择一个数字问最小值 r e s res res,所有权值之和是 s u m sum sum,答案就是 s u m − r e s . sum - res. sumres.

f ( i ) f(i) f(i):在前 i i i 头牛里面选,方案最大值。那么不选第 i i i 头牛的话就是 f ( i ) = f ( i − 1 ) f(i) = f(i - 1) f(i)=f(i1),当然也可以选择从 i − j + 1 ∼ i i - j + 1 \sim i ij+1i 头牛,且不选第 i − j i - j ij 头牛。就是 f ( i − j − 1 ) + s [ i ] − s [ i − j ] f(i - j -1) + s[i] - s[i - j] f(ij1)+s[i]s[ij],记 f ( i − j − 1 ) − s [ i − j ] = g ( i − j ) f(i - j - 1) - s[i - j] = g(i - j) f(ij1)s[ij]=g(ij),即 g ( i ) = f ( i − 1 ) − s [ i ] g(i) = f(i - 1) - s[i] g(i)=f(i1)s[i]. 因此 f ( i ) = max ⁡ { f ( i − 1 ) , g ( i − j ) + s [ i ] } f(i) = \max\{f(i -1), g(i - j) + s[i]\} f(i)=max{f(i1),g(ij)+s[i]}. 因此我们需要找到 max ⁡ \max\limits_{} max

算法模板(4):动态规划(4) 做题积累(2),算法模板,算法,动态规划,图论

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
typedef long long ll;
ll f[N], g[N], q[N], s[N];
int n, k;
int main()
{
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= n; i++)
    {
        scanf("%lld", &s[i]);
        s[i] += s[i - 1];
    }

    int hh = 0, tt = -1;
    q[++tt] = 0;
    for(int i = 1; i <= n; i++)
    {
        if(q[hh] < i - k) hh++;
        f[i] = max(f[i - 1], g[q[hh]] + s[i]);
        g[i] = f[i - 1] - s[i];
        while(hh <= tt && g[q[tt]] <= g[i]) tt--;
        q[++tt] = i;
    }

    printf("%lld\n", f[n]);
    return 0;
}

4. 1091. 理想的正方形

  • 题意:有一个 a × b a\times b a×b 的整数组成的矩阵,现请你从中找出一个 n × n n\times n n×n 的正方形区域,使得该区域所有数中的最大值和最小值的差最小。
  • 二维单调队列,求方框内的最大值和最小值.

保存一个二维单调队列 d e q u e < i n t > c o l [ M ] deque<int> col[M] deque<int>col[M],记录第 j j j 列的滑动窗口最大值;以及当前行的单调队列 d e q u e < i n t > r o w deque<int>row deque<int>row,记录方框内 c o l [ j − k + 1 : j ] . f r o n t ( ) col[j - k + 1:j].front() col[jk+1:j].front() 的最大值。每次先用 w [ i , j ] w[i,j] w[i,j] 更新第 j j j 列的状态(即 c o l [ j ] . b a c k ( ) col[j].back() col[j].back()),再用 c o l [ j ] . f r o n t ( ) col[j].front() col[j].front() 更新 r o w row row 的状态.

这道题卡时间了,然后我把 O1 O2 O3 优化全开了,然后就过了.

#include<bits/stdc++.h>
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define x first
#define y second

using namespace std;
const int N = 1010;
typedef pair<int, int> P;
deque<int> col_max[N], col_min[N];
deque<P> row_max, row_min;
int n, m, k;
int w[N][N];
int ans = 0x3f3f3f3f;
int main()
{
    scanf("%d%d%d", &n, &m, &k);
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            scanf("%d", &w[i][j]);
        }
    }
    for(int i = 1; i <= n; i++)
    {
        row_max.clear(), row_min.clear();
        for(int j = 1; j <= m; j++)
        {
            if(col_max[j].size() && col_max[j].front() < i - k + 1) col_max[j].pop_front();
            if(col_min[j].size() && col_min[j].front() < i - k + 1) col_min[j].pop_front();
            if(row_max.size() && row_max.front().y < j - k + 1) row_max.pop_front();
            if(row_min.size() && row_min.front().y < j - k + 1) row_min.pop_front();

            while(col_max[j].size() && w[col_max[j].back()][j] <= w[i][j]) col_max[j].pop_back();
            col_max[j].push_back(i);
            while(col_min[j].size() && w[col_min[j].back()][j] >= w[i][j]) col_min[j].pop_back();
            col_min[j].push_back(i);

            while(row_max.size() && row_max.back().x <= w[col_max[j].front()][j]) row_max.pop_back();
            row_max.push_back({w[col_max[j].front()][j], j});
            while(row_min.size() && row_min.back().x >= w[col_min[j].front()][j]) row_min.pop_back();
            row_min.push_back({w[col_min[j].front()][j], j});

            if(i >= k && j >= k)
            {
                ans = min(ans, row_max.front().x - row_min.front().x);
            }
        }
    }
    printf("%d\n", ans);
}

10. 斜率优化DP(凸包优化)

1.1 301. 任务安排2

1.2 302. 任务安排3

N N N 个任务排成一个序列在一台机器上等待执行,它们的顺序不得改变。机器会把这 N N N 个任务分成若干批,每一批包含连续的若干个任务。从时刻 0 0 0 开始,任务被分批加工,执行第 i i i 个任务所需的时间是 T i T_i Ti。另外,在每批任务开始前,机器需要 S S S 的启动时间,故执行一批任务所需的时间是启动时间 S S S 加上每个任务所需时间之和。一个任务执行后,将在机器中稍作等待,直至该批任务全部执行完毕。也就是说,同一批任务将在同一时刻完成。每个任务的费用是它的完成时刻乘以一个费用系数 C i C_i Ci。请为机器规划一个分组方案,使得总费用最小。

情况一:
  • 1 ≤ n ≤ 5000 , 0 ≤ S ≤ 50 , 1 ≤ T i , C i ≤ 100 1 \le n \le 5000,0\le S \le 50,1 \le T_i,C_i \le 100 1n5000,0S50,1Ti,Ci100. 用 O ( n 2 ) O(n^2) O(n2) 来写

f ( i ) f(i) f(i) 为分配任务 1 ∼ i 1 \sim i 1i 的最小花费。假设上一批最后一个任务编号是 j j j. 那么,新分配一个任务的对答案多出来的启动时间的花费是 S ∗ ( s u m C n − s u m C j ) S * (sumC_n - sumC_j) S(sumCnsumCj) ,任务本身的花费是 s u m T i ∗ ( s u m C i − s u m C j ) sumT_i*(sumC_i - sumC_j) sumTi(sumCisumCj). 即 f ( i ) = min ⁡ 0 ≤ j < i { f ( j ) + s u m T i ∗ ( s u m C i − s u m C j ) + S ∗ ( s u m C n − s u m C j ) } f(i) = \min\limits_{0 \le j < i} \{ f(j) + sumT_i*(sumC_i - sumC_j) + S * (sumC_n - sumC_j)\} f(i)=0j<imin{f(j)+sumTi(sumCisumCj)+S(sumCnsumCj)}.

#include<bits/stdc++.h>
using namespace std;
const int N = 5010;
int f[N], sumC[N], sumT[N];
int n, S;
int main()
{
    scanf("%d%d", &n, &S);
    for(int i = 1; i <= n; i++)
    {
        scanf("%d%d", &sumT[i], &sumC[i]);
        sumT[i] += sumT[i - 1], sumC[i] += sumC[i - 1];
    }
    
    memset(f, 0x3f, sizeof f);
    f[0] = 0;
    
    for(int i = 1; i <= n; i++)
    {
        for(int j = 0; j < i; j++)
        {
            f[i] = min(f[i], f[j] + sumT[i] * (sumC[i] - sumC[j]) + S * (sumC[n] - sumC[j])); 
        }
    }
    printf("%d\n", f[n]);
    return 0;
}
情况二
  • 1 ≤ n ≤ 3 ∗ 1 0 5 , 1 ≤ T i , C i ≤ 512 , 0 ≤ S ≤ 512 1 \le n \le 3*10^5,1≤T_i,C_i≤512,0≤S≤512 1n3105,1Ti,Ci512,0S512.
  • 由于和 i i i 相关的可以看作定值,和 j j j 相关的可以看作变量。因此原等式可以这样做变化: f ( j ) = ( s u m T i + S ) ∗ s u m C j + f ( i ) − s u m T i ∗ s u m C i − S ∗ s u m C n f(j) = (sumT_i + S) * sumC_j +f(i) - sumT_i * sumC_i - S * sumC_n f(j)=(sumTi+S)sumCj+f(i)sumTisumCiSsumCn.

可以看作直线 y = k x + b y = kx + b y=kx+b y y y f ( j ) f(j) f(j),斜率是 s u m T i + S sumT_i+S sumTi+S x x x s u m C j sumC_j sumCj,截距 b b b 可以看作 f ( i ) − s u m T i ∗ s u m C i − S ∗ s u m C n f(i) - sumT_i * sumC_i - S * sumC_n f(i)sumTisumCiSsumCn . 而 f ( j ) f(j) f(j) s u m C j sumC_j sumCj 是之前就计算出来的,目标是让 f ( i ) f(i) f(i) 最小,就是让截距最小. 我们发现,如果把 ( s u m C j , f ( j ) ) (sumC_j,f(j)) (sumCj,f(j)) 画在坐标系中,那么可以和答案有关的点一定是在凸包的边界上。这道题的斜率都是正数.

此题特点是斜率单调递增,横坐标也单调递增

在查询的时候,可以将队头小于当前斜率的点全部删掉;在插入的时候,将队尾所有不在凸包上的点全部删掉. 当然对于这个题横坐标 s u m C i sumC_i sumCi 本身就是单调递增的.

因此查询的点一定是一直往右走,因此查询的时候遇到斜率小与 s u m C i sumC_i sumCi 的就可以删掉了(但是要注意与上一个点的相对斜率不一定会比上一个相对斜率大).

算法模板(4):动态规划(4) 做题积累(2),算法模板,算法,动态规划,图论

#include<bits/stdc++.h>
using namespace std;
const int N = 300010;
typedef long long ll;

ll f[N], C[N], T[N], q[N], s;
int n;
int main()
{
    scanf("%d%lld", &n, &s);

    for(int i = 1; i <= n; i++)
    {
        scanf("%lld%lld", &T[i], &C[i]);
        T[i] += T[i - 1], C[i] += C[i - 1];
    }

    int hh = 0, tt = -1;
    q[++tt] = 0;

    for(int i = 1; i <= n; i++)
    {
        while(hh < tt && f[q[hh + 1]] - f[q[hh]] <= (T[i] + s) * (C[q[hh + 1]] - C[q[hh]])) hh++;
        int j = q[hh];
        f[i] = f[j] + T[i] * C[i] + s * C[n] - (T[i] + s) * C[j];
        while(hh < tt && (f[q[tt]] - f[q[tt - 1]]) * (C[i] - C[q[tt]]) >= (f[i] - f[q[tt]]) * (C[q[tt]] - C[q[tt - 1]])) tt--;
        q[++tt] = i;
    }
    printf("%lld\n", f[n]);

    return 0;
}
情况三
  • 1 ≤ n ≤ 3 ∗ 1 0 5 , 0 ≤ S , C i ≤ 512 , − 512 ≤ T i ≤ 512. 1 \le n \le 3 * 10 ^5, 0 \le S,C_i \le 512,-512 \le T_i \le 512. 1n3105,0S,Ci512,512Ti512.

  • 此题特点是斜率可能不单调,但横坐标 s u m C i sumC_i sumCi 仍然是单调递增的.

  • 处理方法是:在查询的时候,只能二分来找;在插入的时候,把不在凸包上的点全部删掉.

补充一句,如果横坐标不单调递增,那么需要有增添操作,那么需要用平衡树维护.

#include<bits/stdc++.h>
using namespace std;
const int N = 300010;
typedef long long ll;
ll s, C[N], T[N], f[N];
int n, q[N];
int main()
{
    scanf("%d%lld", &n, &s);
    for(int i = 1; i <= n; i++)
    {
        scanf("%lld%lld", &T[i], &C[i]);
        T[i] += T[i - 1], C[i] += C[i - 1];
    }

    int hh = 0, tt = -1;
    q[++tt] = 0;
    for(int i = 1; i <= n; i++)
    {
        int l = hh, r = tt;
        //考虑清楚二分的边界.
        while(l < r)
        {
            int mid = (l + r) / 2;
            if((f[q[mid + 1]] - f[q[mid]]) > (__int128)(T[i] + s) * (C[q[mid + 1]] - C[q[mid]])) r = mid;
            else l = mid + 1;
        }

        int j = q[l];
        f[i] = f[j] + (__int128)T[i] * C[i] + (__int128)s * C[n] - (__int128)(T[i] + s) * C[j];
        while(hh < tt && (__int128)(f[q[tt]] - f[q[tt - 1]]) * (C[i] - C[q[tt]]) >= (__int128)(f[i] - f[q[tt]]) * (C[q[tt]] - C[q[tt - 1]])) tt--;
        q[++tt] = i;
    }
    printf("%lld\n", f[n]);
    return 0;
}

303. 运输小猫

  • S S S 是农场主,他养了 M M M 只猫,雇了 P P P 位饲养员。农场中有一条笔直的路,路边有 N N N 座山,从 1 1 1 N N N 编号。第 i i i 座山与第 i − 1 i−1 i1 座山之间的距离为 D i D_i Di。饲养员都住在 1 1 1 号山。第 i i i 只猫去 H i H_i Hi 号山玩,玩到时刻 T i T_i Ti 停止,然后在原地等饲养员来接。饲养员在路上行走需要时间,速度为 1 米/单位时间。你的任务是规划每个饲养员从 1 号山出发的时间,使得所有猫等待时间的总和尽量小。饲养员出发的时间可以为负。

  • d d d 是前缀和, t t t 是结束时间,那么,对于第 i i i 只猫,只有饲养员在 t i − d i t_i - d_i tidi 之后出发才能接到这只猫。因此我们设 a i = t i − d i a_i = t_i - d_i ai=tidi,那么按照 a a a 排序,一位饲养员接一段连续子序列的小猫,那么相当于把这个子序列分为不超过 P P P 份,每位饲养员恰好接到当前子序列的最后一只小猫. 假设饲养员是 s i s_i si 出发的,恰好接到小猫 i i i,那么小猫等待时间就是 s i − a i . s_i - a_i. siai.

  • f ( j , i ) f(j, i) f(j,i) 为第 j j j 只饲养员接的最后一只小猫是 i i i. 上一个饲养员接的小猫是 k k k,那么 f ( j , i ) = min ⁡ { f ( j − 1 , k ) + a i ∗ ( i − k ) − ( s i − s k ) } f(j,i) = \min \{f(j - 1, k) + a_i * (i - k) - (s_i - s_k)\} f(j,i)=min{f(j1,k)+ai(ik)(sisk)}.

f ( j − 1 , k ) + s k = a i ∗ k + f ( j , i ) − a i ∗ i + s i f(j - 1,k) + s_k = a_i * k + f(j, i) - a_i * i + s_i f(j1,k)+sk=aik+f(j,i)aii+si.文章来源地址https://www.toymoban.com/news/detail-532425.html

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 100010, M = 100010, P = 110;

int n, m, p;
LL d[N], t[N], a[N], s[N];
LL f[P][M];
int q[M];

LL get_y(int k, int j)
{
    return f[j - 1][k] + s[k];
}

int main()
{
    scanf("%d%d%d", &n, &m, &p);

    for (int i = 2; i <= n; i ++ )
    {
        scanf("%lld", &d[i]);
        d[i] += d[i - 1];
    }

    for (int i = 1; i <= m; i ++ )
    {
        int h;
        scanf("%d%lld", &h, &t[i]);
        a[i] = t[i] - d[h];
    }

    sort(a + 1, a + m + 1);

    for (int i = 1; i <= m; i ++ ) s[i] = s[i - 1] + a[i];

    memset(f, 0x3f, sizeof f);
    for (int i = 0; i <= p; i ++ ) f[i][0] = 0;

    for (int j = 1; j <= p; j ++ )
    {
        int hh = 0, tt = 0;
        q[0] = 0;

        for (int i = 1; i <= m; i ++ )
        {
            while (hh < tt && (get_y(q[hh + 1], j) - get_y(q[hh], j)) <= a[i] * (q[hh + 1] - q[hh])) hh ++ ;
            int k = q[hh];
            f[j][i] = f[j - 1][k] - a[i] * k + s[k] + a[i] * i - s[i];
            while (hh < tt && (get_y(q[tt], j) - get_y(q[tt - 1], j)) * (i - q[tt]) >=
                (get_y(i, j) - get_y(q[tt], j)) * (q[tt] - q[tt - 1])) tt -- ;
            q[ ++ tt] = i;
        }
    }

    printf("%lld\n", f[p][m]);

    return 0;
}

作者:yxc
链接:https://www.acwing.com/activity/content/code/content/128992/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

11. 基环树DP

359. 创世纪

12. 四边形不等式DP

13. 插头DP

14. 环形与后效性处理

15. 倍增优化 DP

16. 数据结构优化 DP

到了这里,关于算法模板(4):动态规划(4) 做题积累(2)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 算法模板(3):搜索(4):高等图论

    相关概念 强连通分量:Strongly Connected Component (SCC). 对于一个有向图顶点的子集 S S S ,如果在 S S S 内任取两个顶点 u u u 和 v v v ,都能找到一条 u u u 到 v v v 的路径,那么称 S S S 是强连通的。 如果在强连通的顶点集合 S S S 中加入其他任意顶点集合后,它都不再是强连通的,那

    2024年02月08日
    浏览(44)
  • 算法模板(3):搜索(3):图论提高

    (1)朴素版prim算法( O ( n 2 ) O(n ^ 2) O ( n 2 ) ) 适用范围:稠密图 易错:注意有向图还是无向图;注意有没有重边和负权边。 从一个集合向外一个一个扩展,最开始只有 1 1 1 这个结点,然后把元素一个一个加进来,每次加的元素就是离这个集合距离最小的元素,可以设为

    2024年02月09日
    浏览(44)
  • 【图论C++】树的直径(DFS 与 DP动态规划)

    UpData Log👆 2023.9.27 更新进行中 Statement0🥇 一起进步 Statement1💯 有些描述是个人理解,可能不够标准,但能达其意 21-1-1 定义 树上 最远的两个节点之间 的距离被称为 树的直径 ,连接这两个点的路径 被称为 树的最长链 。 21-1-2 性质 1 、这两个最远点一定是叶子节点 1、这 两

    2024年02月07日
    浏览(43)
  • 【算法入门&图论】【模板】拓扑排序|【模板】单源最短路2 |最小生成树

    ✅作者简介:热爱后端语言的大学生,CSDN内容合伙人 ✨精品专栏:C++面向对象 🔥系列专栏:算法百炼成神 本专栏收录的均为牛客网的算法题目,内含链表、双指针、递归、动态规划、基本数据结构等算法思想的具体运用。牛客网不仅有大量的经典算法题目,也有大厂的面

    2024年02月03日
    浏览(46)
  • 【C++算法模板】图论-拓扑排序,超详细注释带例题

    推荐视频链接:D01 拓扑排序 给定一张 有向无环图 ,排出所有顶点的一个序列 A A A 满足:对于图中的每条有向边 ( x , y ) (x,y) ( x , y ) , x x x 在 A A A 中都出现在 y y y 之前,则称 A A A 是该图的顶点的一个拓扑序 拓扑排序 可以判断有向图中是否有环,可以生成拓扑序列 对于下

    2024年04月15日
    浏览(41)
  • C++动态规划模板汇总大全

    如果你不太了解dp(动态规划)是个什么东西,请回到上次dp。 链接:动态规划算法详解 【题目描述】 观察下面的数字金字塔。写一个程序查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以从当前点走到左下方的点也可以到达右下方的点。 在上

    2024年02月06日
    浏览(34)
  • 动态规划之最长公共子序列模板

    夏令营:动态规划特训 - 【算法模板题】最长公共子序列 - 蓝桥云课 (lanqiao.cn) 我们来解释一下状态转移方程吧。 dp[i][j]的含义是第i个和第j个字符,i与j的下标从1开始,代表着原子符串的第一个字符。那么理所当然字符串a的第0个字符和字符串b的0个字符的公共长度为0.如果字

    2024年02月12日
    浏览(46)
  • 图论做题笔记:bfs

    题目: 基因序列可以表示为一条由 8 个字符组成的字符串,其中每个字符都是  \\\'A\\\' 、 \\\'C\\\' 、 \\\'G\\\'  和  \\\'T\\\'  之一。 假设我们需要调查从基因序列  start  变为  end  所发生的基因变化。一次基因变化就意味着这个基因序列中的一个字符发生了变化。 例如, \\\"AACCGGTT\\\" -- \\\"AACCGGTA

    2024年04月09日
    浏览(43)
  • 【动态规划】最强最详细的思路及模板(C++)

    本文根据力扣动态规划精讲(一)(二)(三)的框架编写。 动态规划精讲(一) - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台 目录 一 动态规划问题的特征 1.1 重叠子问题:子问题反复出现(递归树可以很清晰地看出) 1.2 最优子结构 1.3 贪心和动态规划的区别

    2024年02月08日
    浏览(32)
  • 最短路Dijkstra,spfa,图论二分图算法AYIT---ACM训练(模板版)

    最短路Dijkstra,spfa,图论二分图算法AYIT—ACM训练(模板版) A — Dijkstra B — spfa/Dijkstra C — 二分图 D — 二分图 E — 二分图 F — 二分图 G — Dijkstra H — Topsort Dijkstra算法基础模板题 💬 模板演示: 朴素版本Dijkstra: 💬 代码演示: 🚩 运行结果: spfa算法: 💬 代码演示: 🚩

    2024年02月10日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包