UVa 11748 Rigging Elections

题目描述

在一个采用一对一淘汰制的选举系统中,每周从候选人池中选出两个人进行对决,败者被淘汰,胜者回到候选人池。这个过程持续到只剩下一个候选人。作为选举的主持人,你可以每周选择哪两个候选人对决。你有一个偏爱的候选人 ccc,并且拥有所有选民的排名数据。问题是:能否通过合理安排对决顺序,让你偏爱的候选人 ccc 最终获胜?

输入格式

每个测试用例的第一行包含三个整数 nnnmmmccc

  • nnn:候选人总数 (1≤n≤1001 \leq n \leq 1001n100)
  • mmm:选民人数 (1≤m≤1001 \leq m \leq 1001m100,且为奇数)
  • ccc:你偏爱的候选人编号 (1≤c≤n1 \leq c \leq n1cn)

接下来是 mmm 行,每行是一个 111nnn 的排列,表示一个选民对所有候选人的排名。输入以三个 000 结束。

输出格式

对于每个测试用例,输出一行 yesno,表示是否能让候选人 ccc 获胜。

题目分析

问题本质

这个问题实际上是一个**竞赛图(Tournament Graph\texttt{Tournament Graph}Tournament Graph中的潜在胜者(Potential Winner\texttt{Potential Winner}Potential Winner)**问题。我们需要判断候选人 ccc 是否有可能通过某种对决顺序成为最后的赢家。

关键观察

  1. 对决规则:当两个候选人对决时,选民会投票给在自己排名中位置更靠前的候选人。

  2. 胜负关系:对于任意两个候选人 iiijjj,我们可以通过统计所有选民的偏好来确定 iii 是否能击败 jjj。如果超过半数的选民在排名中将 iii 放在 jjj 前面,那么 iii 就能击败 jjj

  3. 获胜条件:候选人 ccc 能够获胜的充分必要条件是:从 ccc 出发,存在一条路径可以到达所有其他候选人。这意味着 ccc 可以通过一系列的对决(可能不是直接对决)击败所有其他候选人。

为什么这个条件成立?

假设候选人 ccc 能够通过某种对决顺序成为最后的赢家。考虑任意其他候选人 xxx,在 cccxxx 对决之前,xxx 必须已经被淘汰,或者 ccc 直接击败 xxx。如果 xxx 被其他候选人 yyy 淘汰,那么 ccc 必须能够击败 yyy(直接或间接)。这形成了一个从 cccxxx 的击败链。

反过来,如果从 ccc 到所有其他候选人都存在路径,我们可以按照拓扑排序的逆序安排对决:先让那些被 ccc 间接击败的候选人对决,胜者再与 ccc 对决,这样 ccc 就能最终获胜。

解题思路

算法步骤

  1. 构建胜负关系图

    • 对于每对候选人 (i,j)(i, j)(i,j),统计在所有选民排名中 iii 排在 jjj 前面的次数。
    • 如果这个次数超过 m/2m/2m/2(由于 mmm 是奇数,所以严格大于),则添加一条从 iiijjj 的有向边,表示 iii 能击败 jjj
  2. 检查可达性

    • 从候选人 ccc 开始进行广度优先搜索(BFS\texttt{BFS}BFS)或深度优先搜索(DFS\texttt{DFS}DFS)。
    • 检查是否能够访问到所有 nnn 个候选人。
  3. 输出结果

    • 如果从 ccc 可以到达所有其他候选人,输出 yes
    • 否则,输出 no

复杂度分析

  • 构建胜负关系图需要 O(n2⋅m)O(n^2 \cdot m)O(n2m) 的时间,因为对于每对候选人,我们需要检查所有 mmm 个选民的排名。
  • BFS\texttt{BFS}BFSDFS\texttt{DFS}DFS 需要 O(n2)O(n^2)O(n2) 的时间,因为最多有 n2n^2n2 条边。
  • 总体复杂度为 O(n2⋅m)O(n^2 \cdot m)O(n2m),在 n≤100n \leq 100n100m≤100m \leq 100m100 的约束下是完全可行的。

代码实现

// 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 获胜。

这种将实际问题抽象为图论模型的方法在竞赛中非常常见,掌握这种思维方式对于解决类似问题非常有帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值