news 2026/8/28 22:13:22

Floyd算法与二分搜索:图论最短路优化在环境治理问题中的应用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Floyd算法与二分搜索:图论最短路优化在环境治理问题中的应用

1. 问题引入:从“环境治理”到图论中的最短路优化

最近在复盘蓝桥杯的历年真题,2022年国赛A组的“环境治理”这道题给我留下了挺深的印象。它初看像是一个模拟或者贪心问题,但仔细分析后,会发现其核心是一个图论问题,并且需要结合二分搜索来寻找最优解。题目背景设定为治理城市间的灰尘度,目标是使所有城市间的“灰尘度”降低到某个目标值以下,同时最小化总治理天数。这个“灰尘度”在题目中,本质上就是图中任意两城市间的最短路径长度。所以,问题的内核就变成了:我们如何通过有限的操作(每天选择一个城市进行治理,降低其所有出边和入边的权值),来让整个图的全源最短路径的最大值(即“灰尘度”的最大值)尽快达标。

这让我想起了在实际项目中遇到的一些场景,比如网络延迟优化、数据中心节点间的通信成本降低等。你有一个初始的网络状态(对应初始的邻接矩阵),每天你可以投入资源优化某个节点(降低其与其他节点的连接成本),目标是在最短时间内让整个网络的“最坏情况”连接成本(即所有节点对之间的最大最短路径)低于一个可接受的阈值。这种“通过局部优化驱动全局指标”的思路,在资源调度、性能调优等领域其实挺常见的。

解决这个问题,我们需要两个核心算法工具:Floyd算法用于快速计算任意两点间的最短路径,以及二分法用于高效地搜索那个最小的满足条件的治理天数。直接一天天模拟治理过程并计算最短路径,在数据规模稍大时必然超时。二分法则能将指数级的搜索空间压缩到对数级,是处理这类“最小化最大天数”问题的利器。接下来,我们就拆解一下如何将这两个算法组合起来,啃下这块硬骨头。

2. 核心模型抽象:将治理问题转化为图论判定问题

要应用二分法,首先得能把原问题转化成一个判定性问题。原问题是:找到最小的天数D,使得经过D天治理后,所有城市对间的灰尘度(最短路径)都不超过目标值P。

我们反过来思考:如果给定一个天数D,我们能否判断,经过不超过D天的治理后,能否让所有灰尘度不超过P?如果能高效地回答这个“是或否”的问题,那么我们就可以用二分法来试探不同的D,快速逼近那个最小的、能让答案为“是”的D。

那么,关键就在于如何构建这个判定逻辑。题目规定,每天只能治理一个城市,治理会使该城市的所有出边和入边的灰尘度减少1(但不能低于下限L)。假设我们给定了总天数D,我们需要判断是否存在一种治理方案(即决定每天治理哪个城市),使得最终的全源最短路最大值不超过P。

这里有一个重要的简化思路:对于每个城市,我们并不关心具体在哪一天被治理,只关心它在D天内总共被治理了多少天。因为治理的效果是累加的,治理k天,就意味着与该城市相关的所有边的权值总共可以减少k(当然,不能低于L)。因此,问题从“安排一个D天的序列”简化为“为每个城市分配一个治理天数k_i,使得所有k_i之和等于D,并且经过治理后的图满足条件”。

这进一步引导我们思考:给定每个城市的治理天数k_i,最终的边权如何确定?假设初始边权为G[i][j],治理后,边(i, j)的权值变为max(L, G[i][j] - k_i - k_j)。因为边(i, j)连接了城市i和j,如果i被治理了k_i天,j被治理了k_j天,那么这条边总共会被影响(k_i + k_j)次(每次治理i或j,这条边的权值都会减1)。

于是,判定问题可以重新表述为:是否存在一组非负整数k_0, k_1, ..., k_{n-1},满足sum(k_i) = D,并且对于这样调整后的边权矩阵,用Floyd算法计算出的全源最短路中,最大值不超过P?

直接求解这个存在性判定依然复杂,因为k_i的组合很多。我们需要一个更巧妙的构造方法。注意到,我们的目标是让最短路最大值不超过P。一个更强的条件是:如果我们能直接构造出一个边权矩阵A,使得A[i][j] >= max(L, G[i][j] - x_i - x_j)对于某个{x_i}成立,并且A矩阵本身的全源最短路最大值就不超过P,那么原问题就一定有解。因为我们可以通过实际治理(k_i = x_i)得到比A更优或相等的图。

实际上,我们可以采用一种贪心逼近的思路来构造这个A矩阵,也就是我们熟知的“治理后”的图。对于给定的总天数D,我们如何分配这些天数给各个城市,能最有效地降低全图最短路的最大值?一个直观的策略是优先治理那些处于“枢纽”位置、对全图最短路影响最大的城市。但在判定性问题中,我们不需要找到最优分配,只需要判断是否存在一种分配。

我们可以换一个角度:二分答案D,然后检查在D天内,我们能否通过治理,使得最终的任意两点间最短路径长度不超过P。检查的过程,可以转化为一个最短路约束下的流量分配问题,或者更直接地,利用Floyd算法的动态规划特性进行逆向推导。

但在这里,一个更简洁、更通用的方法是:在二分搜索的每一步,我们“模拟”治理过程,直接修改原始邻接矩阵,然后运行Floyd,检查结果。如何模拟?我们需要计算出在D天内,每个城市最多能被治理多少次。一个显然的上界是D,但实际分配时,总和不能超过D。然而,对于判定“是否存在”,一个充分条件是:我们假设治理能无限理想化地进行,即我们直接尝试用D天来降低整个图的边权。我们可以设计一个函数check(mid),它尝试用mid天来“改善”图,然后判断改善后的图是否满足条件。

具体到实现,一种常见且有效的判定逻辑是:

  1. 根据总天数mid,计算出平均每个城市可以分到的治理天数avg_add = mid / n,以及余数remainder = mid % n
  2. 我们可以认为,每个城市至少可以获得avg_add天的治理。余下的remainder天可以任意分配给remainder个城市(每人多一天)。在判定时,我们可以放宽要求:允许每个城市在avg_add的基础上,最多再增加1天(即最多治理avg_add + 1天)。因为如果存在一种分配方案,那么一定可以通过调整,使得治理天数最多的城市和最少的天数相差不超过1。这是一个很强的必要条件,也几乎总是充分的。
  3. 因此,在check(mid)函数中,我们可以遍历每个城市,计算其治理天数的一个范围[base, base+1],其中base = avg_add。然后,我们需要判断是否存在一种在每个城市治理天数范围内的分配,使得治理后的图满足条件。这仍然是一个搜索问题。
  4. 进一步的简化:我们并不需要精确找出分配方案,只需要判断“即使按照最理想的方式分配(即尽可能多地降低边权),能否达到目标”。因此,我们可以为每条边(i, j)计算一个治理后的可能最小权值min_weight = max(L, G[i][j] - (max_k_i + max_k_j)),其中max_k_imax_k_j是城市i和j可能的最大治理天数(即base+1如果该城市可以被分配额外天数,否则为base)。这样计算出来的min_weight矩阵,代表了在给定天数mid下,我们最多能将该边优化到何种程度。
  5. 然后,对这个min_weight矩阵运行Floyd算法,得到全源最短路。如果所有最短路径中的最大值max_sp满足max_sp <= P,那么说明在mid天内有可能通过某种分配达到目标(因为我们取的是最优情况)。如果即使最优情况都达不到,那么mid天肯定不够。如果最优情况能达到,我们就能说mid天是可能足够的。在二分搜索中,我们就用这个“可能足够”的条件来收缩范围。由于我们总是用最乐观的估计去判断,所以最终二分找到的最小天数ans,需要再验证一下是否真的能构造出方案(通常题目数据会保证这种方法的正确性,或者最终答案就是满足该条件的最小值)。

这个判定逻辑是解决本题的关键跳板。它避免了复杂的组合搜索,将问题转化为一个确定性的计算问题,从而使得二分法得以应用。

3. Floyd算法:计算全源最短路的基石

在我们判定逻辑的核心,需要反复计算一个图的全源最短路径(All-Pairs Shortest Paths, APSP)。对于顶点数n不超过100的稠密图(题目典型范围),Floyd-Warshall算法是不二之选。它的时间复杂度是O(n³),对于n=100,计算量在百万级别,可以接受。更重要的是,它的思想简单,编码不易出错,并且能直接处理邻接矩阵,与我们问题的数据结构完美契合。

Floyd算法的核心是动态规划。定义dist[k][i][j]表示只允许使用顶点0, 1, ..., k作为中间顶点时,从顶点i到顶点j的最短路径长度。那么状态转移方程为:dist[k][i][j] = min(dist[k-1][i][j], dist[k-1][i][k] + dist[k-1][k][j])意思是,从i到j的最短路,要么不经过k(保持原样),要么经过k,即从i到k的最短路加上k到j的最短路。

在实际编码中,我们通常使用滚动数组,将三维数组压缩为二维,直接在原矩阵上迭代:

// 假设 dist 是 n x n 的矩阵,初始化为边的权值(无边则为无穷大) for (int k = 0; k < n; ++k) { for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { if (dist[i][k] != INF && dist[k][j] != INF) { // 防止溢出 dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]); } } } }

这里有一个非常重要的细节:k的循环必须放在最外层。这是因为动态规划的阶段是中间顶点k,我们必须依次考虑将每个顶点加入作为中间点。如果错把i或j放在外层,算法就是错误的,无法正确求出最短路径。

在我们的问题中,每次执行check(mid)函数,我们都需要基于治理后的min_weight矩阵,运行一次完整的Floyd算法,得到全源最短路矩阵,然后找出其中的最大值。这个操作会被二分法调用多次(大约log₂(总天数上限)次),因此Floyd的效率直接影响了整体程序的性能。

踩坑点:无穷大的设置与溢出在Floyd算法中,我们需要用一个很大的数代表“无穷大”(INF),表示两点间没有直接路径或路径尚未发现。但这里有一个经典陷阱:在状态转移dist[i][k] + dist[k][j]时,如果dist[i][k]dist[k][j]是 INF,那么它们的和可能会溢出整型范围,导致比较出错。因此,在上面的代码中,我加了一个判断if (dist[i][k] != INF && dist[k][j] != INF)。另一种更常见的做法是,将 INF 设置为一个比最大可能路径长度大,但又不会导致加法溢出的值,例如0x3f3f3f3f(约10^9),这个值即使两个相加也不会超过32位int上限,并且memset(g, 0x3f, sizeof(g))可以方便地将整个数组初始化为这个值。

4. 二分法搜索:快速锁定最小治理天数

有了判定函数check(mid),我们就可以使用二分搜索来寻找最小的满足条件的天数D。二分法适用于解决这类“最小化最大值”或“最大化最小值”的问题,前提是解空间具有单调性。在我们的问题中,单调性是显然的:如果D天能够治理达标,那么多于D天也一定能达标(因为你可以选择不治理多余的天数)。因此,函数check(D)关于D是单调非递减的。

我们需要确定二分搜索的边界:

  • 左边界 left:显然至少需要0天。但从实际出发,如果0天就已经达标(初始最短路最大值 <= P),那么答案就是0。
  • 右边界 right:一个安全的上界。考虑最坏情况,每条边都需要从初始值治理到下限L。对于一条边(i, j),初始权值为G[i][j],治理到L需要减少(G[i][j] - L)。每天治理只能减少与某个城市相关的所有边1点。一个非常宽松的上界是:假设每条边都独立需要治理,那么总天数上限为n * n * max(G[i][j] - L)。但我们可以更紧凑一些。注意到,治理一个城市会影响其相关的(n-1)条边。在最坏情况下,我们需要将所有边的权值都降到L。那么,总治理次数(边权减少的总量)至少是sum_{i,j} (G[i][j] - L)。每天治理最多可以减少2*(n-1)的边权总量(因为治理一个城市,其相关的(n-1)条边各减1,但每条边连接两个城市,所以总减少量是2*(n-1)?这里需要仔细计算:一天治理城市k,那么对于所有i != k,边(i,k)和(k,i)的权值减1。无向图中,边(i,k)和(k,i)是同一个,所以实际减少的边数是(n-1)条,每条减少1,所以一天减少的总边权是(n-1)。那么,要完成总减少量S = sum_{i<j} (G[i][j] - L) * 2(因为是无向图,矩阵对称),最少需要ceil(S / (n-1))天。我们可以把这个值乘以一个安全系数(比如10),或者简单粗暴地设一个很大的数,如1e9,作为右边界。在竞赛中,通常可以根据数据范围估算,n<=100,G[i][j]<=1e5,那么右边界设为1e72e7是足够安全的。

二分搜索的框架如下:

long long left = 0, right = RIGHT_BOUND, ans = -1; while (left <= right) { long long mid = left + (right - left) / 2; if (check(mid)) { // 如果mid天可行 ans = mid; // 记录当前可行的答案 right = mid - 1; // 尝试寻找更小的可行天数 } else { left = mid + 1; // 当前天数不够,增加天数 } } if (ans == -1) { // 说明即使达到右边界也不可行,根据题意处理(可能输出-1或特定值) } else { cout << ans << endl; }

实操心得:二分查找的细节

  1. 循环条件:使用while (left <= right)可以确保搜索区间完全闭合,避免遗漏解。当left > right时循环结束,此时的ans记录的就是最后一个满足条件的mid,即最小值。
  2. 中间值计算:使用mid = left + (right - left) / 2而非(left + right) / 2,可以防止left+right可能发生的整数溢出。
  3. 更新边界:当check(mid)为真时,说明mid可行,但我们要找的是最小可行解,所以应该到左半区间继续搜索 (right = mid - 1),同时记录当前解。为假时,则到右半区间搜索 (left = mid + 1)。
  4. 答案初始化ans初始化为-1,用于判断是否有解。

5. 判定函数check(mid)的具体实现与优化

这是整个算法中最精妙也最容易出错的部分。我们需要实现前面提到的判定逻辑:给定天数mid,判断是否存在一种治理方案,使得治理后的图其全源最短路最大值不超过P

根据第2部分的推导,我们采用“最优情况估计法”。步骤如下:

  1. 计算基础治理天数base = mid / n。每个城市至少可以治理base天。
  2. 计算额外天数名额extra = mid % n。有extra个城市可以多治理1天。
  3. 构建“最优”治理后矩阵cur:我们需要为每条边(i, j)计算一个尽可能小的权值。对于城市i,其最大可能治理天数为k_i = base + (i < extra ? 1 : 0)。这里采用了一个简单的分配策略:将额外的extra天分配给前extra个城市(编号0到extra-1)。为什么可以这样?因为对于判定“是否存在”,我们只需要一组可行的{k_i}分配,而不需要是最优分配。按顺序分配是一种简单且有效的构造方式。如果存在某种分配使得条件满足,那么通过调整,总可以使得治理天数多的城市排在前面,所以按顺序分配额外天数来测试是合理的。
    • 因此,治理后的边权cur[i][j] = max(L, G[i][j] - k_i - k_j)。注意,G[i][j]是初始边权,k_ik_j是城市i和j的最大可能治理天数。max(L, ...)确保了边权不会低于下限L。
  4. 计算治理后图的全源最短路:对矩阵cur运行 Floyd 算法,得到最短路径矩阵dist
  5. 判定:遍历所有i,j(i != j),找到dist[i][j]的最大值max_dist。如果max_dist <= P,则返回true;否则返回false

这个判定函数的时间复杂度是 O(n³),主要来自Floyd算法。由于它会在二分搜索中被调用 O(log(right)) 次,所以总时间复杂度约为 O(n³ * log(right)),对于n<=100是完全可以接受的。

关键点与边界情况处理

  • 对称性:题目中的道路是无向的,所以初始矩阵G是对称的。我们构建的cur矩阵也保持对称。
  • 自环:城市到自身的距离应该为0。在初始化dist矩阵时,需要设置dist[i][i] = 0。在治理计算cur[i][i]时,我们通常不关心,因为自环不会影响最短路计算。
  • 下限 Lmax(L, ...)操作至关重要。它模拟了治理的物理限制:灰尘度不能无限降低。在计算cur[i][j]时,如果G[i][j] - k_i - k_j < L,那么结果就是L。
  • 整数类型:治理天数、边权、最短路长度在累加过程中可能很大,需要使用long long类型来避免溢出。特别是在计算G[i][j] - k_i - k_j时,即使G[i][j]intk_ik_j也可能是较大的整数(base可能很大),所以提升到long long计算是安全的。

6. 从理论到实践:完整代码框架与调试技巧

将以上所有部分组合起来,就得到了完整的解题代码。下面给出一个清晰的C++实现框架,并附上关键注释:

#include <iostream> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; const int N = 110; // 最大城市数 const LL INF = 1e18; // 定义一个足够大的无穷大 LL G[N][N]; // 初始灰尘度矩阵 LL dist[N][N]; // Floyd算法中的距离矩阵 int n; LL P, L; // 检查在total_days天内能否治理达标 bool check(LL total_days) { // 1. 计算每个城市的基础治理天数和额外天数分配 LL base = total_days / n; int extra = total_days % n; // 2. 构建治理后的边权矩阵 cur LL cur[N][N]; for (int i = 0; i < n; ++i) { LL k_i = base + (i < extra ? 1 : 0); // 城市i的治理天数 for (int j = 0; j < n; ++j) { LL k_j = base + (j < extra ? 1 : 0); // 城市j的治理天数 // 治理后的边权,不能低于L cur[i][j] = max(L, G[i][j] - k_i - k_j); } } // 3. 初始化Floyd距离矩阵 for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { dist[i][j] = cur[i][j]; } dist[i][i] = 0; // 自身到自身的距离为0 } // 4. 运行Floyd算法 for (int k = 0; k < n; ++k) { for (int i = 0; i < n; ++i) { // 一个小优化:如果dist[i][k]已经是INF,则跳过j循环 if (dist[i][k] == INF) continue; for (int j = 0; j < n; ++j) { if (dist[k][j] == INF) continue; dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]); } } } // 5. 检查全源最短路的最大值是否不超过P LL max_dist = 0; for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { if (i == j) continue; if (dist[i][j] > max_dist) { max_dist = dist[i][j]; } } } return max_dist <= P; } int main() { // 读入数据 cin >> n >> P >> L; for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { cin >> G[i][j]; } } // 特判:如果0天就已经达标 // 这里需要先对原始图G跑一次Floyd,判断初始状态 // 为了代码简洁,我们将其融入二分搜索,左边界从0开始即可 // 设定二分边界 LL left = 0, right = 1e9; // 右边界可以根据题目数据范围调整,这里设一个较大的值 LL ans = -1; while (left <= right) { LL mid = left + (right - left) / 2; if (check(mid)) { ans = mid; right = mid - 1; // 寻找更小的可行天数 } else { left = mid + 1; } } if (ans == -1) { // 根据题目要求,如果无解可能需要输出特定值,例如-1 // 但根据题目描述,通常保证有解 cout << -1 << endl; } else { cout << ans << endl; } return 0; }

调试与验证技巧:

  1. 小数据测试:自己构造n=2, 3的小样例,手动计算治理过程和最短路径,验证程序输出。
  2. 边界测试
    • 初始状态就满足max_dist <= P的情况,答案应为0。
    • L值很大的情况:如果L大于所有初始边权,那么治理无效,答案取决于初始状态。
    • 总天数需要很大的情况:测试二分上界是否足够。
  3. 中间输出:在调试时,可以在check(mid)函数中打印出mid,base,extra,以及治理后的cur矩阵和计算出的max_dist,帮助理解程序的执行过程。
  4. 复杂度分析:确认算法复杂度在题目限制内。本题n<=100,O(n³ * log(1e9)) ≈ 1e8 量级,在C++中通常可以接受。
  5. 对比暴力:对于非常小的n(如n<=5),可以写一个暴力枚举所有治理方案的程序,与二分法的结果进行对比,确保判定逻辑的正确性。

7. 算法总结与思维延伸

回顾这道“环境治理”题,它的巧妙之处在于将一个看似是模拟或规划的问题,通过图论建模和二分答案,转化为了一个可计算的问题。核心步骤是:

  1. 建模:将城市视为点,道路灰尘度视为边权,治理操作视为减少与某个点相连的所有边的权值。
  2. 转化:将求最小天数问题,转化为对天数D的判定问题。
  3. 判定:设计check(D)函数,通过贪心分配治理天数,构造一个“最优可能”的治理后图,并用Floyd算法验证其是否满足条件。
  4. 搜索:利用二分法快速找到最小的满足条件的D。

这种“二分答案 + 判定函数”的框架,在算法竞赛和实际工程中都非常有用。凡是遇到“最小化最大值”这类问题,并且验证一个候选解比直接求解更容易时,都可以考虑这个思路。

思维延伸与变种考虑:

  1. 治理效果非线性:如果治理一天不是减少1点,而是减少一个变量值,或者有递减效应,那么判定函数中cur[i][j] = max(L, G[i][j] - k_i - k_j)的计算就需要修改。
  2. 多目标治理:如果不是要求所有点对的最短路径最大值达标,而是要求平均值达标,或者要求达标点对的比例,那么判定函数中的检查条件就需要改变。
  3. 更高效的APSP算法:如果n更大(比如n=500),O(n³)的Floyd算法可能太慢。可以考虑更快的算法,如Johnson算法(O(n² log n + n m)),但对于稠密图,Floyd的常数小,且编码简单,往往是首选。也可以考虑在二分判定时,是否需要用全源最短路?有时可能只需要检查某些特定指标。
  4. 并行化:在实际工程中,如果图的规模很大,Floyd算法可以通过分块、并行计算来加速。判定函数check(mid)彼此独立,也可以并行执行多个二分割试探。

解决这道题的过程,是一次典型的算法思维训练:分析问题本质、建立数学模型、设计高效算法、注意边界细节。它综合考察了对图论、二分搜索、动态规划(Floyd)的理解和应用能力。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/28 22:10:34

终于懂了!PaperXie查重不对标知网定稿|是超大优势不是缺点✅

很多同学之前误会太深&#xff01;误以为PaperXie查重无法等同于知网、维普学校定稿系统是缺陷&#xff0c;实则恰恰相反——这是PaperXie独有的核心优势&#xff0c;也是它最护学生、最合规、最不容易翻车的关键原因。 市面上很多查重工具故意虚假标榜“100%对标学校定稿系统…

作者头像 李华
网站建设 2026/8/28 22:06:31

Java 各类锁对比・诗意化记忆

偏向锁、轻量级锁、重量级锁、synchronized、Lock、ReentrantLock、读写锁、自旋锁、乐观悲观锁&#xff0c;古风记忆&#xff0c;适配面试。总起并发多线程争疆场&#xff0c;资源抢夺起刀枪。 锁分乐观与悲观&#xff0c;轻重偏向各行藏。 隐显两套把门户&#xff0c;自旋忙等…

作者头像 李华
网站建设 2026/8/28 22:05:34

C# 工业设备通讯系列(持续更新中...)

文章目录 C# 工业设备通讯系列技术博文&#xff08;持续更新...&#xff09;第一篇&#xff1a;【C# 工业通讯】封装一个健壮的 TCP Socket 客户端基类&#xff08;心跳与异常处理&#xff09; 核心痛点解决方案&#xff1a;通用客户端基类设计关键技术点&#xff1a;核心代码实…

作者头像 李华
网站建设 2026/8/28 22:02:30

MATLAB预测模型实战:从灰色预测到神经网络,掌握四大核心算法

1. 从“猜”到“算”&#xff1a;预测模型到底在做什么&#xff1f; 每次看到“预测”两个字&#xff0c;很多人第一反应是“算命”或者“瞎猜”。尤其是在数学建模竞赛里&#xff0c;新手拿到一个预测类题目&#xff0c;比如“预测未来五年的城市用电量”、“估计下个月某商品…

作者头像 李华
网站建设 2026/8/28 22:02:28

C++11 std::function与std::bind:可调用对象封装与适配实战

1. 从“函数对象”到“可调用对象”&#xff1a;C11的范式跃迁如果你是从C98/03时代一路走过来的老手&#xff0c;肯定对“仿函数”&#xff08;Functor&#xff09;这个概念不陌生。那时候&#xff0c;想让一个东西像函数一样被调用&#xff0c;最正统的做法就是定义一个类&am…

作者头像 李华
网站建设 2026/8/28 22:00:26

蓝桥杯算法题解析:状态压缩DP在网格计数问题中的应用

1. 从一道蓝桥杯算法题看“绘制地图”的抽象与实现 最近在整理蓝桥杯的历年练习题&#xff0c;翻到了ALGO-380这道名为“绘制地图”的题目。说实话&#xff0c;第一次看到这个标题&#xff0c;我脑海里浮现的是各种图形库、画布操作&#xff0c;甚至想到了游戏开发里的地图编辑…

作者头像 李华