1 条题解

  • 0
    @ 2025-4-5 18:47:59

    算法标签:

    拓扑排序

    题解:

    这道题的核心在于依据给定的一组形如 “A < B” 的关系,来判定是能够确定一个升序的排序序列,还是存在关系不一致的情况,亦或是无法确定排序序列。代码采用拓扑排序算法解决此问题,具体思路为:首先进行输入处理,读取要排序的对象数量 n 以及关系数量 m,随后在循环中读取 m 个关系,将这些关系存储于邻接矩阵 mp 中,并同步更新每个节点的入度 in。接着进行拓扑排序,每次读取一个关系后,调用 Topo 函数。在 Topo 函数内,先把原始入度复制到 inn 数组,防止对原始入度造成修改,然后进行 n 次循环,每次都去寻找一个入度为 0 的节点。若在某次循环中未找到入度为 0 的节点,那就表明存在环,此时返回 - 1;若在某次循环中找到多个入度为 0 的节点,意味着排序不唯一,将 f 标记为 0;而每次找到一个入度为 0 的节点后,需将其入度减 1,同时把与该节点相邻的节点的入度也减 1。最后进行结果判断,若 Topo 函数返回 0,说明无法确定排序序列;若返回 - 1,说明存在环,即关系不一致;若返回 1,说明已经确定排序序列,此时再次调用 Topo 函数输出排序结果。

    #include <iostream>
    #include <cstring>
    using namespace std;
    
    const int MAXN = 26;
    int in[MAXN], inn[MAXN], n;
    int mp[MAXN][MAXN];
    
    // 拓扑排序函数,op 为 1 时输出排序结果,为 0 时不输出
    int Topo(int op) {
        int i, j, k, f = 1;
        // 将原始入度复制到 inn 数组,避免修改原始入度
        for (i = 0; i < n; ++i)
            inn[i] = in[i];
        // 进行 n 次循环,每次找出一个入度为 0 的节点
        for (i = 0; i < n; ++i) {
            k = -1;
            // 遍历所有节点,找出入度为 0 的节点
            for (j = 0; j < n; ++j) {
                if (!inn[j]) {
                    // 如果已经找到过入度为 0 的节点,说明排序不唯一
                    if (k != -1) f = 0;
                    k = j;
                }
            }
            j = k;
            // 如果没有找到入度为 0 的节点,说明存在环,返回 -1
            if (j == -1) return -1;
            // 如果 op 为 1,输出当前节点对应的字母
            if (op) cout << char('A' + j);
            // 将当前节点的入度减 1,标记为已处理
            inn[j]--;
            // 遍历所有节点,将与当前节点相邻的节点的入度减 1
            for (k = 0; k < n; ++k)
                inn[k] -= mp[j][k];
        }
        // 如果 op 为 1,输出换行符
        if (op)
            cout << "." << endl;
        // 返回排序结果,1 表示排序唯一,0 表示排序不唯一
        return f;
    }
    
    int main() {
        int f, m, i, a, b, x;
        string st;
        while (cin >> n >> m && n && m) {
            // 初始化邻接矩阵和入度数组
            memset(mp, 0, sizeof(mp));
            memset(in, 0, sizeof(in));
            // f 用于标记是否已经确定排序结果,x 用于记录处理的关系数量
            f = 0;
            x = -1;
            // 循环读取 m 个关系
            for (i = 1; i <= m; ++i) {
                cin >> st;
                // 获取关系中的两个节点
                a = st[0] - 'A';
                b = st[2] - 'A';
                // 如果是大于关系,交换 a 和 b
                if (st[1] == '>') {
                    a += b;
                    b = a - b;
                    a -= b;
                }
                // 如果已经确定排序结果,跳过后续关系
                if (f) continue;
                // 更新邻接矩阵和入度
                mp[a][b]++;
                in[b]++;
                // 调用拓扑排序函数进行判断
                f = Topo(0);
                // 记录当前处理的关系数量
                x = i;
            }
            // 如果 f 为 0,说明无法确定排序序列
            if (!f) cout << "Sorted sequence cannot be determined." << endl;
            // 如果 f 为 -1,说明存在环,关系不一致
            else if (f == -1) cout << "Inconsistency found after " << x << " relations." << endl;
            // 否则,说明已经确定排序序列
            else {
                cout << "Sorted sequence determined after " << x << " relations: ";
                // 再次调用拓扑排序函数输出排序结果
                Topo(1);
            }
        }
        return 0;
    }
    
    • 1

    信息

    ID
    95
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者