当前位置:首页 > 蓝桥杯 > 2016年蓝桥杯省赛B组交换瓶子题解(洛谷P8637)| 解题思路与代码优化

2016年蓝桥杯省赛B组交换瓶子题解(洛谷P8637)| 解题思路与代码优化

2周前 (09-03)

2016年蓝桥杯省赛B组交换瓶子题解(洛谷P8637)| 解题思路与代码优化 蓝桥杯省赛 并查集 环形结构 洛谷 C++ 第1张

一、题目解读

题目要求将N个瓶子通过交换操作使其编号与位置对应(即每个瓶子指向自身)。每个瓶子初始指向另一个瓶子位置,需计算最小交换次数。例如,当瓶子i指向瓶子j时,交换i与j的位置可使两者指向自身。题目关键在于识别环形结构并计算交换次数。

二、解题思路

并查集(Union-Find)思想优化解题:

1. 将每个瓶子视为节点,初始各节点自成环。

2. 遍历时标记已访问节点,识别出每个连通环(即闭合路径)。

3. 每个环的交换次数为环大小-1(最后一个节点无需交换)。

4. 累加所有非单节点环的交换次数,得到最终结果。

核心在于利用环结构特性减少无效交换计算。

三、解题步骤

1. 输入处理:读取N及每个瓶子的指向位置,存储于bottles数组(1-based索引)。

2. 初始化标记:使用visited数组记录节点是否被遍历。

3. 循环遍历:

    对每个未访问节点i,启动新环遍历。

    通过while循环跟踪链i → bottles[i] →...直至回到起点(形成环)。

    标记路径上所有节点,记录环大小cycleSize。

4. 交换次数计算:若环大小>1,则需cycleSize-1次交换(单节点环无需交换)。

5. 输出结果:累加所有环的交换次数并输出。

四、代码与注释

#include <iostream>
#include <vector>
using namespace std;

int main() {
   int N;
   cin >> N;
   vector<int> bottles(N + 1);  // 使用1-based索引
   vector<bool> visited(N + 1, false);
   
   // 读取输入
   for (int i = 1; i <= N; ++i) {
       cin >> bottles[i];
   }
   
   int swapCount = 0;
   
   // 遍历每个瓶子
   for (int i = 1; i <= N; ++i) {
       if (!visited[i]) {   // 未访问节点为新环起点
           // 开始一个新的环
           int current = i;
           int cycleSize = 0;
           
           // 遍历整个环
           while (!visited[current]) {
               visited[current] = true;  // 标记已访问
               current = bottles[current];  // 跟踪指向节点
               cycleSize++;              // 环大小+1
           }
           
           // 每个大小为k的环需要k-1次交换
           if (cycleSize > 1) {
               swapCount += (cycleSize - 1);
           }
       }
   }
   
   cout << swapCount << endl;
   return 0;
}

注释说明:

● visited数组用于避免重复遍历已处理的环。

● cycleSize记录当前环的节点数,通过累加遍历次数计算。

● 最终交换次数仅累加非单节点环的贡献,避免冗余计算。

五、总结

本解法通过并查集思想将问题转化为环计数,有效降低时间复杂度。关键在于识别闭合路径并优化交换次数计算逻辑。代码简洁且易于理解,适用于处理具有环形结构的交换问题。掌握此类算法思维对编程竞赛中复杂路径问题的解决具有重要价值。

参考:2016蓝桥杯省赛B组交换瓶子题解

原创内容 转载请注明出处

分享给朋友:

相关文章

【深度优先搜索实战】力扣547题:省份数量问题的图论解法

【深度优先搜索实战】力扣547题:省份数量问题的图论解法

题目解读‌我们面对的是一个典型的图论问题:给定一个城市的连接矩阵,需要计算其中相互连通的城市群(省份)数量。这个问题可以抽象为无向图中的连通分量计算,每个城市代表图中的一个节点,城市之间的连接关系代表...

力扣145:递归之美 轻松掌握二叉树后序遍历

力扣145:递归之美 轻松掌握二叉树后序遍历

题目解读二叉树的后序遍历是一种基础且重要的树遍历方式,其遍历顺序为:先递归地后序遍历左子树,然后递归地后序遍历右子树,最后访问根节点。这种遍历方式特别适合需要先处理子节点再处理父节点的场景,如内存释放...

力扣540题:线性扫描法如何高效定位唯一数

力扣540题:线性扫描法如何高效定位唯一数

题目重解一个严格递增的有序数组中,除某个元素外,其余每个元素均出现两次。这个看似简单的条件背后隐藏着巧妙的规律——单一元素会打破数组的"成对对称性"。题目要求以O(log n)时间...

【蓝桥杯2015省赛解析】生命之树:树形DP解题全攻略(洛谷P8625代码详解)

【蓝桥杯2015省赛解析】生命之树:树形DP解题全攻略(洛谷P8625代码详解)

一、题目解读    “生命之树”是一道经典的树形结构问题,要求计算一棵带权树中,以某个节点为根的最大子树权值和。题目输入为n个节点及边信息,每个节点有权值wi,...

力扣3112题解法:带时间限制的最短路径问题解析(C++代码)

力扣3112题解法:带时间限制的最短路径问题解析(C++代码)

一、题目解读力扣3112题要求解决带时间限制的最短路径问题:给定一个有向图,节点具有消失时间,需计算从起点到各节点的最短路径,且路径总时间不能超过节点的消失时间。题目难点在于需在传统最短路径算法(如D...

【洛谷1184题解析】用C++高效解决地点匹配问题(附代码与解题思路)

【洛谷1184题解析】用C++高效解决地点匹配问题(附代码与解题思路)

一、题目解读洛谷1184题要求处理一组地点列表与行程记录,统计其中匹配的天数。题目难点在于高效处理带有空格的字符串输入,以及快速判断每日行程是否在高手可去地点集合中。需要兼顾输入格式解析与算法效率。二...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。