P1878 舞蹈课 结构体优先队列,重载运算符
解题思路
本题需要模拟舞蹈课上学生配对跳舞的过程,关键点在于:
-
异性相邻配对:只有相邻的男生('B')和女生('G')才能配对
-
最小差值优先:优先选择舞蹈技术差值最小的一对
-
左边优先:当有多对差值相同时,选择最左边的一对
-
动态更新:每次配对后,队伍会合并,需要动态维护新的相邻关系
算法选择
使用优先队列+双向链表的解决方案:
-
优先队列:用于快速获取当前差值最小的相邻对
-
双向链表:维护队伍中学生的左右邻居关系,方便动态更新
代码注释
#include<bits/stdc++.h> #define pii pair<int,int> #define ll long long using namespace std; const int N = 2e5 + 10; int n; string s; ll a[N], vis[N], left_node[N], right_node[N]; // a存储舞蹈技术值,vis标记是否已配对 pii ans[N]; // 存储配对结果 int top; // 记录配对数 // 自定义结构体,存储配对信息 struct Pair { ll diff; // 舞蹈技术差值 ll x, y; // 配对的两个学生编号 // 重载小于运算符,用于优先队列排序 bool operator<(const Pair& other) const { if(diff != other.diff) return diff > other.diff; // 差值小的优先 return x > other.x; // 差值相同时,编号小的优先 } }; priority_queue<Pair> q; // 优先队列,存储所有可能的配对 int main() { ios::sync_with_stdio(false); cin.tie(0); // 输入处理 cin >> n >> s; for(int i = 1; i <= n; i++) cin >> a[i]; s = '.' + s; // 让字符串下标从1开始 // 初始化双向链表 for(int i = 1; i <= n; i++) { left_node[i] = i - 1; // 左邻居 right_node[i] = i + 1; // 右邻居 } right_node[n] = 0; // 末尾没有右邻居 // 初始化优先队列,找出所有初始相邻异性对 for(int i = 2; i <= n; i++) { if(s[i] != s[i-1]) { // 如果是异性相邻 q.push({abs(a[i] - a[i-1]), i-1, i}); // 计算差值并加入队列 } } // 处理配对过程 while(!q.empty()) { auto current = q.top(); q.pop(); int x = current.x, y = current.y; // 如果任一学生已经配对过,跳过 if(vis[x] || vis[y]) continue; // 记录配对结果 vis[x] = vis[y] = 1; ans[++top] = {min(x,y), max(x,y)}; // 更新双向链表 int l = left_node[x], r = right_node[y]; if(l) right_node[l] = r; // x的左邻居指向y的右邻居 if(r) left_node[r] = l; // y的右邻居指向x的左邻居 // 检查新形成的相邻对是否可以配对 if(l && r && s[l] != s[r] && !vis[l] && !vis[r]) { q.push({abs(a[l] - a[r]), l, r}); } } // 输出结果 cout << top << endl; for(int i = 1; i <= top; i++) { cout << ans[i].first << " " << ans[i].second << endl; } return 0; }
关于运算符重载的详细说明
在结构体Pair中重载了operator<运算符,这是为了定义优先队列中的排序规则:
bool operator<(const Pair& other) const { if(diff != other.diff) return diff > other.diff; // 差值小的优先 return x > other.x; // 差值相同时,编号小的优先 }
这里有几个关键点需要注意:
-
默认优先队列是最大堆,即默认使用
less比较,较大的元素优先级高 -
我们想要的是差值最小的优先,所以当
diff > other.diff时返回true,这样较小的diff会被认为"更小"(优先级更高) -
当差值相同时,我们想要编号较小的优先,所以当
x > other.x时返回true,这样较小的x会被认为"更小"
这种设计确保了优先队列总是能返回:
-
舞蹈技术差值最小的对
-
当差值相同时,最左边的对(即编号较小的对)
示例解析
以题目中的输入为例:
4 BGBG 4 2 4 3
初始相邻异性对:
-
(1,2): |4-2|=2
-
(2,3): |2-4|=2
-
(3,4): |4-3|=1
处理过程:
-
取出(3,4)配对,队伍变为B B G
-
新相邻对(2,3)但都是B,不配对
-
取出(1,2)配对
最终输出:
2 3 4 1 2

浙公网安备 33010602011771号