洛谷P7916 [CSP-S 2021]交通规划

该博客详细介绍了如何解决洛谷P7916题目中的交通规划问题,针对k≤2的情况,通过分析和计算分界线上边权之和,转化为最短路问题。对于k=3的情况,通过点的配对和最短路求解,利用括号序列的区间DP找到最小边权和。博主还给出了具体的代码实现并添加注释以便理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


如果你没有学习过对偶图等知识,那么对你来说其他题解可能有点难理解,但这篇题解不会!在阅读这篇题解之前,你不需要掌握任何高深的知识,就可以学会这道题的做法

Part1 k ⩽ 2 k\leqslant 2 k2的情况

Step1 分析

首先, k = 1 k=1 k=1的情况非常简单,你只需要把所有点染成相同颜色即可,这时候答案为 0 0 0,显然是最小的
而对于 k = 2 k=2 k=2且两个附加点颜色相同,则和上面一样,答案为 0 0 0
所以我们只考虑 k = 2 k=2 k=2且两个点异色的情况
下面以样例为例子来解释我们的算法
题目样例
在这张图中,灰色的方块表示每一个点,灰色的块中的黑、白点指的是这个点的颜色
我们考虑染色结束后的情况,此时,我们可以把这张图分为若干个黑、白连通块,如图所示
分成若干连通块

假设此时有多于一个块是黑色的,那么这些块的四周一定都是白色的点(否则就是一个连通块而不是两个了),所以这就出现了一个问题:我为什么不把这些黑色的块中的每个点都染成白色呢?这样的话,答案就可以减小很多
例如上图中的右下角的连通块,如果把它改为白色,答案可以减少 5 + 7 = 12 5+7=12 5+7=12
同理可知,同样也只有一个白色的块
所以,我们可以找到一条分界线,把黑色和白色的点分在这条线的两侧
分界线
从图上可以看出,只有被线穿过的边的两侧的点才是异色的,所以我们需要统计的就是这条分界线所穿过的线的权值之和了!

Step2 计算分界线上边权之和

现在,我们的问题转化成了:在这张图上找一条线,使得这条线把这张图分为两块,并且线上的边权之和最小
好,看看上面的那张图,如果我们把每一条边的边权当做是红色的折线(即分界线)的每段线上的边权之和,这一问题不就转化成了最短路的问题了吗?
对偶图
在这张图中,左上角和右下角的两个点就是最短路的起点和终点,没有数字的边意味着这条边的权值为 0 0 0,也就是说,我们可以从左上部的任意一个点,走到右下部的任意一个点
从图中可以看出,最短的路径就是 3 + 4 + 5 = 12 3+4+5=12 3+4+5=12,把这条路径当做分割线,将原图分为两半染色后,所求的答案就是 3 + 4 + 5 = 12 3+4+5=12 3+4+5=12
我们接着考虑一个小优化,为的是让建图的过程变得简便,我们把整张图变为一个矩形,在无用的虚边上将权值设置为 0 0 0,如图:
优化为矩形
我们可以看到,起点和终点分别位于两个附加点连成的线的两侧,这是因为一条分割线一定经过两个附加点的不同侧,否则无法把它们两个分开,所以两个点必须在不同侧
这样,我们就成功地解决了 k ⩽ 2 k\leqslant 2 k2的情况,得到了 36 36 36

Part2 正解

Step1 k = 3 k=3 k=3

这时候,肯定有两个点是同色的,如何处理有同色点时起点和终点的位置呢?
我们将样例稍作改动:
样例2
这时候,有两个白色的附加点,那么我们可以把这两个点当成同一个点进行处理:
缩点
这样的话,我们就可以知道起点和终点的位置了!
样例2对偶图
这样,我们就可以解决 k = 3 k=3 k=3的情况了

Step2 配对

通过上面的 k = 3 k=3 k=

### CSP-S 2021 交通规划 解题报告 #### 题目背景与描述 交通规划问题涉及在一个城市网络中寻找最优路径。给定一个带权有向图,每条边有权重表示通过这条道路所需的时间。对于每次查询,需要找到从起点到终点的最短路径。 #### 使用Dijkstra算法求解单源最短路径 针对此类问题的一种有效方法是对每次询问执行一次 Dijkstra 算法即可[^1]。此策略适用于动态变化的城市地图场景,在这种情况下,仅当无边界节点发生变化时才需重新构建这些特定节点。这种方法能够确保即使在网络拓扑发生局部变动的情况下也能高效计算新的最短路径。 #### 数据结构的选择——链表的应用 考虑到可能存在的大量重复操作以及频繁的数据项移除需求,采用链表来管理数据可以显著提升效率。具体来说,可以通过数组模拟实现双向链表的功能,从而允许快速定位并处理相邻元素之间的关系。相比于直接使用线性表进行逐个删除的操作(这可能导致O(n²)级别的性能开销),利用链表可以在常数时间内完成插入和删除动作,极大地提高了程序运行速度[^2]。 #### 特殊情况下的优化技巧 为了进一步减少不必要的计算量,应当考虑如何有效地识别并合并具有相同特性的连续子序列。例如,在遇到多个相连且属性一致的对象时,可以直接将其视为单一整体来进行后续运算;一旦发现两段原本分离但现在变得完全相等的部分,则立即实施融合操作以简化模型结构。这样的做法不仅有助于降低空间占用率,同时也加快了整个系统的响应速率[^4]。 ```python from heapq import heappop, heappush def dijkstra(graph, start): dist = {node: float('inf') for node in graph} prev = {} pq = [(0, start)] while pq: current_distance, u = heappop(pq) if current_distance > dist[u]: continue for v, weight in graph[u].items(): distance = current_distance + weight if distance < dist[v]: dist[v] = distance prev[v] = u heappush(pq, (distance, v)) return dist, prev ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值