题目描述
在一个采用一对一淘汰制的选举系统中,每周从候选人池中选出两个人进行对决,败者被淘汰,胜者回到候选人池。这个过程持续到只剩下一个候选人。作为选举的主持人,你可以每周选择哪两个候选人对决。你有一个偏爱的候选人 ccc,并且拥有所有选民的排名数据。问题是:能否通过合理安排对决顺序,让你偏爱的候选人 ccc 最终获胜?
输入格式
每个测试用例的第一行包含三个整数 nnn、mmm 和 ccc:
- nnn:候选人总数 (1≤n≤1001 \leq n \leq 1001≤n≤100)
- mmm:选民人数 (1≤m≤1001 \leq m \leq 1001≤m≤100,且为奇数)
- ccc:你偏爱的候选人编号 (1≤c≤n1 \leq c \leq n1≤c≤n)
接下来是 mmm 行,每行是一个 111 到 nnn 的排列,表示一个选民对所有候选人的排名。输入以三个 000 结束。
输出格式
对于每个测试用例,输出一行 yes 或 no,表示是否能让候选人 ccc 获胜。
题目分析
问题本质
这个问题实际上是一个**竞赛图(Tournament Graph\texttt{Tournament Graph}Tournament Graph)中的潜在胜者(Potential Winner\texttt{Potential Winner}Potential Winner)**问题。我们需要判断候选人 ccc 是否有可能通过某种对决顺序成为最后的赢家。
关键观察
-
对决规则:当两个候选人对决时,选民会投票给在自己排名中位置更靠前的候选人。
-
胜负关系:对于任意两个候选人 iii 和 jjj,我们可以通过统计所有选民的偏好来确定 iii 是否能击败 jjj。如果超过半数的选民在排名中将 iii 放在 jjj 前面,那么 iii 就能击败 jjj。
-
获胜条件:候选人 ccc 能够获胜的充分必要条件是:从 ccc 出发,存在一条路径可以到达所有其他候选人。这意味着 ccc 可以通过一系列的对决(可能不是直接对决)击败所有其他候选人。
为什么这个条件成立?
假设候选人 ccc 能够通过某种对决顺序成为最后的赢家。考虑任意其他候选人 xxx,在 ccc 与 xxx 对决之前,xxx 必须已经被淘汰,或者 ccc 直接击败 xxx。如果 xxx 被其他候选人 yyy 淘汰,那么 ccc 必须能够击败 yyy(直接或间接)。这形成了一个从 ccc 到 xxx 的击败链。
反过来,如果从 ccc 到所有其他候选人都存在路径,我们可以按照拓扑排序的逆序安排对决:先让那些被 ccc 间接击败的候选人对决,胜者再与 ccc 对决,这样 ccc 就能最终获胜。
解题思路
算法步骤
-
构建胜负关系图:
- 对于每对候选人 (i,j)(i, j)(i,j),统计在所有选民排名中 iii 排在 jjj 前面的次数。
- 如果这个次数超过 m/2m/2m/2(由于 mmm 是奇数,所以严格大于),则添加一条从 iii 到 jjj 的有向边,表示 iii 能击败 jjj。
-
检查可达性:
- 从候选人 ccc 开始进行广度优先搜索(BFS\texttt{BFS}BFS)或深度优先搜索(DFS\texttt{DFS}DFS)。
- 检查是否能够访问到所有 nnn 个候选人。
-
输出结果:
- 如果从 ccc 可以到达所有其他候选人,输出
yes。 - 否则,输出
no。
- 如果从 ccc 可以到达所有其他候选人,输出
复杂度分析
- 构建胜负关系图需要 O(n2⋅m)O(n^2 \cdot m)O(n2⋅m) 的时间,因为对于每对候选人,我们需要检查所有 mmm 个选民的排名。
- BFS\texttt{BFS}BFS 或 DFS\texttt{DFS}DFS 需要 O(n2)O(n^2)O(n2) 的时间,因为最多有 n2n^2n2 条边。
- 总体复杂度为 O(n2⋅m)O(n^2 \cdot m)O(n2⋅m),在 n≤100n \leq 100n≤100 和 m≤100m \leq 100m≤100 的约束下是完全可行的。
代码实现
// Rigging Elections
// UVa ID: 11748
// Verdict: Accepted
// Submission Date: 2025-11-16
// UVa Run Time: 0.000s
//
// 版权所有(C)2025,邱秋。metaphysis # yeah dot net
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m, c;
while (cin >> n >> m >> c && (n || m || c)) {
vector<vector<int>> ballots(m, vector<int>(n));
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
cin >> ballots[i][j];
}
}
vector<vector<bool>> beat(n + 1, vector<bool>(n + 1, false));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (i == j) continue;
int wins = 0;
for (int k = 0; k < m; k++) {
int posI = find(ballots[k].begin(), ballots[k].end(), i) - ballots[k].begin();
int posJ = find(ballots[k].begin(), ballots[k].end(), j) - ballots[k].begin();
if (posI < posJ) wins++;
}
if (wins > m / 2) beat[i][j] = true;
}
}
vector<bool> visited(n + 1, false);
queue<int> q;
q.push(c);
visited[c] = true;
int count = 1;
while (!q.empty()) {
int u = q.front();
q.pop();
for (int v = 1; v <= n; v++) {
if (!visited[v] && beat[u][v]) {
visited[v] = true;
count++;
q.push(v);
}
}
}
if (count == n) cout << "yes\n";
else cout << "no\n";
}
return 0;
}
总结
本题的关键在于将选举问题转化为图论中的可达性问题。通过构建候选人之间的胜负关系图,并检查偏爱候选人 ccc 是否能到达所有其他候选人,我们可以判断是否存在一种对决顺序让 ccc 获胜。
这种将实际问题抽象为图论模型的方法在竞赛中非常常见,掌握这种思维方式对于解决类似问题非常有帮助。
3909

被折叠的 条评论
为什么被折叠?



