UVa 12263 Rankings

题目描述

nnn 支队伍(编号从 111nnn)每年参加编程竞赛,比赛结束后会按成绩优劣进行排名。已知去年的排名列表。今年,组委会希望降低比赛的竞争性,决定不发布完整的排名列表(因为排名靠后的队伍可能会灰心)。相反,他们会发布一个完整的配对列表,这些配对中的两支队伍在去年和今年的相对排名顺序发生了变化。

例如,如果去年队伍 131313 排在队伍 666 前面,但今年队伍 666 排在队伍 131313 前面,那么就会公布配对 (6,13)(6, 13)(6,13)。这样可以让队伍跟踪他们与特定对手的进展,但不会给他们一个清晰的总体排名情况。

当然,这不会阻止你的队伍尝试确定总体排名列表。给定去年的排名和所有相对排名顺序发生变化的队伍配对列表,尽可能重构出今年的排名情况。如果给出的数据与任何可能的今年排名列表不一致,你也应该检测到这种情况。

输入格式

  • 第一行:一个正整数,表示测试用例的数量(最多 100100100 个)
  • 每个测试用例包含:
    • 一行一个整数 nnn (2≤n≤5002 \leq n \leq 5002n500):队伍数量
    • 一行 nnn 个整数 tit_iti (1≤ti≤n1 \leq t_i \leq n1tin):去年的排名,从最好的队伍到最差的队伍
    • 一行一个整数 mmm (0≤m≤250000 \leq m \leq 250000m25000):相对排名顺序发生变化的配对数量
    • mmm 行,每行两个整数 aia_iaibib_ibi (1≤ai<bi≤n1 \leq a_i < b_i \leq n1ai<bin):相对排名顺序发生变化的队伍配对

输出格式

每个测试用例输出:

  • 一行 nnn 个整数:今年的排名,从最好到最差,如果某个位置无法确定,用 ? 代替。如果数据与任何可能的排名列表不一致,输出 IMPOSSIBLE

题目分析

问题本质

这是一个典型的拓扑排序问题,但需要处理两种特殊情况:

  1. 不一致性检测:当约束关系存在环时,无法形成有效的排名
  2. 不确定性处理:当拓扑排序过程中有多个选择时,相应位置的结果不确定

关键观察

  1. 排名关系的传递性:如果 AAA 排在 BBB 前面,BBB 排在 CCC 前面,那么 AAA 必须排在 CCC 前面
  2. 约束关系的建立
    • 根据去年的排名,我们可以知道所有队伍之间的完整相对顺序
    • 对于发生变化的配对,今年的顺序与去年相反
    • 对于未发生变化的配对,今年的顺序与去年相同

解题思路

  1. 建立关系矩阵

    • 首先构建一个 n×nn \times nn×n 的矩阵 lastYearOrder,记录去年所有队伍之间的相对顺序
    • 如果队伍 iii 去年排在队伍 jjj 前面,则 lastYearOrder[i][j] = true
  2. 更新今年关系

    • 初始化 thisYearOrder 为去年的关系
    • 对于每个变化的配对 (a,b)(a, b)(a,b),交换 thisYearOrder[a][b]thisYearOrder[b][a] 的值
  3. 构建有向图

    • 将每个队伍作为图的一个节点
    • 如果 thisYearOrder[i][j] = true,则添加一条从 iiijjj 的有向边,表示 iii 排在 jjj 前面
  4. 拓扑排序

    • 计算每个节点的入度
    • 使用队列进行拓扑排序
    • 在排序过程中:
      • 如果队列中同时有多个节点可选,说明结果不确定
      • 如果最终排序结果包含的节点数不等于 nnn,说明存在环,数据不一致
  5. 输出结果

    • 存在环 → 输出 IMPOSSIBLE
    • 排序过程中有多个选择 → 输出 ?
    • 否则 → 输出确定的排名

算法复杂度分析

  • 时间复杂度O(n2+m)O(n^2 + m)O(n2+m),其中 nnn 是队伍数量,mmm 是变化配对数量
  • 空间复杂度O(n2)O(n^2)O(n2),主要用于存储关系矩阵

代码实现

// Rankings
// UVa ID: 12263
// Verdict: Accepted
// Submission Date: 2025-11-29
// UVa Run Time: 0.020s
//
// 版权所有(C)2025,邱秋。metaphysis # yeah dot net

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 505;

vector<int> topologicalSort(int n, vector<vector<int>>& graph, vector<int>& indegree) {
    vector<int> result;
    queue<int> q;
    
    // 找到所有入度为0的节点
    for (int i = 1; i <= n; i++) {
        if (indegree[i] == 0) {
            q.push(i);
        }
    }
    
    bool multiple = false;  // 是否有多个选择
    
    while (!q.empty()) {
        if (q.size() > 1) {
            multiple = true;  // 有多个节点可选,结果不确定
        }
        
        int current = q.front();
        q.pop();
        result.push_back(current);
        
        // 更新相邻节点的入度
        for (int neighbor : graph[current]) {
            indegree[neighbor]--;
            if (indegree[neighbor] == 0) {
                q.push(neighbor);
            }
        }
    }
    
    // 如果结果数量不等于n,说明有环
    if (result.size() != n) {
        return vector<int>();  // 返回空向量表示不可能
    }
    
    // 如果有多个选择,标记为不确定
    if (multiple) {
        return vector<int>(n, -1);  // 用-1表示不确定
    }
    
    return result;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int testCases;
    cin >> testCases;
    
    while (testCases--) {
        int n;
        cin >> n;
        
        vector<int> lastYear(n);
        for (int i = 0; i < n; i++) {
            cin >> lastYear[i];
        }
        
        // 构建去年的排名关系矩阵
        vector<vector<bool>> lastYearOrder(n + 1, vector<bool>(n + 1, false));
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                lastYearOrder[lastYear[i]][lastYear[j]] = true;
            }
        }
        
        int m;
        cin >> m;
        
        // 初始化今年的关系矩阵(开始时与去年相同)
        vector<vector<bool>> thisYearOrder = lastYearOrder;
        
        // 处理变化的关系
        for (int i = 0; i < m; i++) {
            int a, b;
            cin >> a >> b;
            // 交换a和b的关系
            swap(thisYearOrder[a][b], thisYearOrder[b][a]);
        }
        
        // 构建图
        vector<vector<int>> graph(n + 1);
        vector<int> indegree(n + 1, 0);
        
        // 根据今年的关系构建有向图
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                if (i != j && thisYearOrder[i][j]) {
                    graph[i].push_back(j);
                    indegree[j]++;
                }
            }
        }
        
        // 进行拓扑排序
        vector<int> result = topologicalSort(n, graph, indegree);
        
        if (result.empty()) {
            // 存在环,不可能
            cout << "IMPOSSIBLE\n";
        } else if (result[0] == -1) {
            // 结果不确定
            for (int i = 0; i < n; i++) {
                if (i > 0) cout << " ";
                cout << "?";
            }
            cout << "\n";
        } else {
            // 确定的结果
            for (int i = 0; i < n; i++) {
                if (i > 0) cout << " ";
                cout << result[i];
            }
            cout << "\n";
        }
    }
    
    return 0;
}

总结

本题通过将排名问题转化为图论中的拓扑排序问题,巧妙地解决了排名关系的约束和传递性问题。关键在于:

  1. 正确建立约束关系:利用去年的完整排名和变化配对构建今年的相对顺序
  2. 处理特殊情况:检测环的存在(不一致性)和拓扑排序的多解性(不确定性)
  3. 高效实现:使用邻接矩阵存储关系,队列实现拓扑排序

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值