题解:AtCoder AT_awc0043_b Pairing for the Dance Party
【题目来源】
AtCoder:B - Pairing for the Dance Party (atcoder.jp)
【题目描述】
Takahashi has been put in charge of organizing the school's dance party. There are \(N\) participants, each numbered from \(1\) to \(N\).
高桥被任命负责组织学校的舞会。有 \(N\) 名参与者,编号从 \(1\) 到 \(N\)。
At the dance party, participants form pairs to dance together. However, this school has a unique tradition: each participant \(i\) has a positive integer value called "priority" \(R_i\). A person with higher priority (larger value) has the right to choose their partner first.
在舞会上,参与者会结成对一起跳舞。然而,这所学校有一个独特的传统:每位参与者 \(i\) 有一个称为"优先级"的正整数值 \(R_i\)。优先级更高(值更大)的人有权先选择自己的舞伴。
Aoki is participant number \(1\), and he is concerned about who his partner will be.
青木是编号为 \(1\) 的参与者,他很关心自己的舞伴会是谁。
\(M\) "pair candidates" have been designated in advance from among the participants. The \(j\)-th pair candidate is the pair of participant \(U_j\) and participant \(V_j\), meaning that participant \(U_j\) and participant \(V_j\) are candidates to be paired with each other. Pairs can only be formed from these \(M\) candidates.
从参与者中预先指定了 \(M\) 个"配对候选"。第 \(j\) 个配对候选是参与者 \(U_j\) 和参与者 \(V_j\) 组成的对,这意味着参与者 \(U_j\) 和参与者 \(V_j\) 是彼此的配对候选。配对只能从这 \(M\) 个候选中形成。
The pairing rules are as follows:
配对规则如下:
- Set all \(N\) participants' partners as undetermined.
将所有 \(N\) 名参与者的舞伴状态设为未确定。 - Among the participants whose partner is undetermined, select the one participant with the highest priority \(R_i\). Call this participant \(x\).
在舞伴未确定的参与者中,选择优先级 \(R_i\) 最高的一名参与者。称此参与者为 \(x\)。 - Among the participants who are pair candidates with participant \(x\) and whose partner is undetermined, select the one with the smallest participant number. Call this participant \(y\). Pair participant \(x\) with participant \(y\).
在舞伴未确定且与参与者 \(x\) 是配对候选的参与者中,选择编号最小的参与者。称此参与者为 \(y\)。将参与者 \(x\) 与参与者 \(y\) 配对。 - Repeat steps 2–3 until there are no participants with undetermined partners.
重复步骤 2–3,直到没有舞伴未确定的参与者。
By this rule, a total of \(N / 2\) pairs are formed (\(N\) is guaranteed to be even).
根据此规则,总共形成 \(N / 2\) 对(保证 \(N\) 是偶数)。
Since all priority values \(R_i\) are distinct, the participant selected in step 2 is uniquely determined. It is also guaranteed that in step 3, participant \(x\) will never have \(0\) available candidates to choose from (that is, the input is guaranteed to allow every participant to be paired with exactly one partner).
由于所有优先级 \(R_i\) 互不相同,步骤 2 中选择的参与者是唯一确定的。同时也保证在步骤 3 中,参与者 \(x\) 永远不会面临 \(0\) 个可选候选的情况(即保证输入允许每位参与者恰好与一位舞伴配对)。
Determine the participant number of Aoki's (participant number \(1\)) partner when the pairs are decided according to this rule.
确定按照此规则决定配对时,青木(参与者编号 \(1\))的舞伴的参与者编号。
【输入】
| \(N\) \(M\) |
| \(R_1\) \(R_2\) \(\ldots\) \(R_N\) |
| \(U_1\) \(V_1\) |
\(U_2\) \(V_2\) \(U_M\) \(V_M\)
- The first line contains \(N\), the number of participants, and \(M\), the number of pair candidates, separated by a space.
- The second line contains the priorities \(R_1, R_2, \ldots, R_N\) of each participant, separated by spaces.
- The following \(M\) lines contain the pair candidate information.
- The \(j\)-th of these lines (the \((2 + j)\)-th line overall) contains participant \(U_j\) and participant \(V_j\) of the \(j\)-th pair candidate, separated by a space.
【输出】
Output the participant number of Aoki's (participant number \(1\)) partner on a single line.
【输入样例】
4 3
10 20 30 40
1 2
1 3
3 4
【输出样例】
2
【核心思想】
-
问题分析:给定 \(N\) 个参与者,每个参与者有优先级 \(R_i\) 和配对候选关系。配对规则是:每次选择优先级最高且未配对的参与者 \(x\),在 \(x\) 的未配对候选者中选择编号最小的 \(y\) 进行配对。求参与者 \(1\)(青木)的配对对象。这是一个贪心 + 优先队列问题,关键在于模拟配对过程。
-
算法选择:
- 最大堆(优先队列):按优先级 \(R_i\) 从大到小排序,每次取出优先级最高的未配对参与者
- 小顶堆数组:为每个参与者维护一个小顶堆,存储其配对候选者(按编号从小到大排序)
- 贪心策略:优先为优先级高的参与者配对,确保高优先级参与者先选择最优搭档
-
关键步骤:
- 读取输入:\(N\)(参与者数量)、\(M\)(候选对数)、\(R[1..N]\)(优先级)、\(M\) 对候选关系 \((U_j, V_j)\)
- 初始化最大堆:将所有参与者按优先级加入最大堆
pq - 构建邻接关系:为每个参与者建立小顶堆
pq2[x],存储其配对候选者 - 贪心配对(当最大堆非空时循环):
- 从最大堆中取出优先级最高的未配对参与者 \(x\)
- 遍历 \(x\) 的候选者小顶堆,找到第一个未配对的候选者 \(y\)
- 将 \(x\) 和 \(y\) 配对,标记两者为已配对
- 输出结果:参与者 \(1\) 的配对对象 \(p[1]\)
-
时间/空间复杂度:
- 时间复杂度:\(O((N + M) \log N)\),优先队列操作
- 空间复杂度:\(O(N + M)\),存储顶点和边信息
-
贪心 + 优先队列的核心思想:
- 贪心策略:优先为优先级高的参与者配对,确保重要参与者先得到配对
- 双堆结构:最大堆处理顶点优先级,小顶堆处理邻居编号,实现 \(O(\log N)\) 的查询和更新
- 模拟过程:严格按照题目规则模拟配对过程,确保结果正确性
- 适用场景:带权顶点配对、优先级调度、资源分配等问题
【算法标签】
堆排序
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
typedef pair<int, int> PII; // 用于存储(值, 编号)对
int n, m; // n: 顶点数, m: 边数
int r[N]; // 顶点的r值
vector<PII> ve[N]; // 邻接表(虽然定义但未使用)
priority_queue<PII> pq; // 最大堆,按r值排序的顶点
priority_queue<int, vector<int>, greater<int> > pq2[N]; // 小顶堆,存储每个顶点的邻居
bool paired[N]; // 标记顶点是否已配对
int p[N]; // 配对结果,p[i]表示与i配对的顶点编号
int main()
{
cin >> n >> m;
// 步骤1:读取每个顶点的r值,并加入最大堆
for (int i = 1; i <= n; i++)
{
cin >> r[i];
pq.push({r[i], i}); // 按r值从大到小排序
}
// 步骤2:读取边,构建邻接关系
for (int i = 1; i <= m; i++)
{
int u, v;
cin >> u >> v;
// 将邻居加入到小顶堆中(按编号从小到大排序)
pq2[u].push(v);
pq2[v].push(u);
}
// 步骤3:贪心配对
while (!pq.empty())
{
auto t = pq.top();
pq.pop();
int x = t.second; // 当前处理的顶点编号
if (paired[x]) // 如果顶点x已配对,跳过
continue;
// 尝试为顶点x找一个未配对的邻居
while (!pq2[x].empty())
{
int y = pq2[x].top(); // 获取x的最小邻居
pq2[x].pop();
if (paired[y]) // 如果邻居y已配对,跳过
continue;
// 找到可配对的邻居y
p[x] = y;
p[y] = x;
paired[x] = true;
paired[y] = true;
break; // 找到配对后退出循环
}
}
// 步骤4:输出顶点1的配对结果
cout << p[1] << endl;
return 0;
}
【运行结果】
4 3
10 20 30 40
1 2
1 3
3 4
2
浙公网安备 33010602011771号