首页 > 其他分享 >洛谷P1347 排序

洛谷P1347 排序

时间:2024-07-10 18:09:55浏览次数:8  
标签:cnt 洛谷 vis int 拓扑 ++ 排序 P1347

传送门

Abstract

这篇题解主要介绍了拓扑排序的唯一性问题和存在性问题。


Idea

要想解决这题需要考虑到一下两点:

  1. 拓扑排序的核心思路在于将所有入度为0的点一次加入序列,如果在某一个时刻图中存在多个入度为0的点,那么我们将无法判断它们的先后顺序,此时,拓扑序列就不唯一了。
  2. 假设有n个点参与拓扑排序,在排序完成以后,我们发现拍好的序列中只有 m(m<n) 个数,怎么回事呢?这说明图中出现了环,如此一来拓扑排序就无法完成了。

考虑到这题给的条件较少 (m<600) ,因此我们可以考虑每加入一个条件就尝试着进行一次拓扑排序,如果当前状态下拓扑排序中出现了环,那么就是矛盾了;如果序列不唯一,那么就需要继续添加条件;如果序列唯一且包含了所有的 n 个字母,那么我们直接结束程序即可。代码实现的细节见下方注释。


Code

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

int n, m;
int in[30], out[30];    // 记录入度出度
vector<vector<int>> fa; // 记录每个字母的父亲字母
bool vis[30];           // 记录此字母是否已经被访问过
int cnt_now;            // 当前已经访问过的字母的数量
int cnt_ruler;          // 当前已经使用的关系数目

// 求解当前状态下,序列是否已经确定/出现矛盾
bool solve()
{
    int ins[30], outs[30]; // 复制出度入度,一遍进行拓扑排序
    memcpy(ins, in, sizeof in), memcpy(outs, out, sizeof out);

    queue<int> q;
    for (int i = 0; i < n; i++)
    {
        if (!vis[i]) // 这个字母还没访问过,那么自然不参与排序
        {
            continue;
        }
        if (outs[i] == 0)
        {
            q.push(i);
        }
    }
    vector<int> ans;         // 储存已经排好的序列
    bool get_unique_ans = 1; // 是否得到唯一的排序
    while (!q.empty())
    {
        if (q.size() > 1) // 当前有超过一个的点出度为0,那么它们的先后顺序是无法判定的
        {
            get_unique_ans = 0;
        }
        int u = q.front(); // 常规拓扑排序,没什么好说的
        q.pop();
        ans.push_back(u);
        for (int i = 0; i < fa[u].size(); i++)
        {
            int v = fa[u][i];
            outs[v]--;
            if (outs[v] == 0)
            {
                q.push(v);
            }
        }
    }
    if (ans.size() < cnt_now) // 如果排好序的序列的长度小于目前已经访问过的字母的数量,说明出现了自环(矛盾)
    {
        cout << "Inconsistency found after " << cnt_ruler << " relations.";
        return 1;
    }
    if (cnt_now == n && ans.size() == n && get_unique_ans) // 已经访问所有字母,且得到唯一排序,直接输出结果
    {
        cout << "Sorted sequence determined after " << cnt_ruler << " relations: ";
        for (int i = 0; i < n; i++)
        {
            char c = char('A' + ans[i]);
            cout << c;
        }
        cout << ".";
        return 1;
    }
    // 既没有矛盾也没有结束,返回false
    return 0;
}

int main()
{
    cin >> n >> m;
    fa.resize(n + 1);
    // 拓扑排序基操,没什么好说的
    for (int i = 0; i < m; i++)
    {
        cnt_ruler++;
        int x, y;
        string text;
        cin >> text;
        x = int(text[0] - 'A'), y = int(text[2] - 'A');
        if (vis[x] == 0)
        {
            cnt_now++;
            vis[x] = 1;
        }
        if (vis[y] == 0)
        {
            cnt_now++;
            vis[y] = 1;
        }
        in[x]++, out[y]++;
        fa[x].push_back(y);
        if (solve()) // 如果得出了矛盾/可解,就直接退出程序
        {
            return 0;
        }
    }
    cout << "Sorted sequence cannot be determined.";
    return 0;
}

标签:cnt,洛谷,vis,int,拓扑,++,排序,P1347
From: https://www.cnblogs.com/carboxylBase/p/18294030

相关文章

  • Python教程:sort和sorted实现排序之对比
    总的来说,sort是应用在列表上的方法,修改原始列表。内建函数sorted可对所有可迭代的对象进行排序操作,返回新的对象。list.sort()方法效率会比sorted(iter)稍微高些。一、sort函数sort()函数用于对原列表进行排序,如果指定参数,则依据指定的函数进行排序。列表才可以进行修......
  • 数据结构--第八章排序
    注:内容参考王道2024考研复习指导以及《数据结构》一、排序的基本概念排序(sort),就是重新排列表中的元素,使表中的元素满足按关键字有序的过程。排序算法的评价指标时间复杂度空间复杂度稳定性算法的稳定性,若待排序表中有两个元素Ri​和Rj​,其对应的关键字相同即keyi​=keyj......
  • 洛谷CF1342B Binary Period题解
    原题解和原题。这道题比较水。这道题分两种情况,分别为$t$由一种字符构成和由两种字符构成两种情况。$t$只有$0$或$1$。此时的$k$就是$1$,直接输出$t$就是最好的选择。$t$既有$0$又有$1$。此时的$k$为$2$,字符串由01或10构成。我们设$a_i$为字符串......
  • 观《深入理解C#有感》--- 排序搜索
    关于在无序列表中,找到所需数据的五种写法classProgram{classProduct{publicstringname;publicintprice;publicoverridestringToString(){returnname;......
  • 洛谷P1073 最优贸易 (分层图)
    题意:多个节点,起点到终点,每个点可以买或卖水晶球,每个点水晶球的价格不一样(买卖价格相同)。问最多买卖一次,能赚取最高多少差价?(在赚不到差价的情况下他就无需进行贸易)。思路:“这个'b'题,我不看题解我是想不出来,但是确实是个很好的题”。有两种做法,双向spfa和分层图,我就只说分层图做法(......
  • 洛谷 P1853 投资的最大效益 蒟蒻题解
    洛谷P1853投资的最大效益蒟蒻题解题目背景约翰先生获得了一大笔遗产,他暂时还用不上这一笔钱,他决定进行投资以获得更大的效益。银行工作人员向他提供了多种债券,每一种债券都能在固定的投资后,提供稳定的年利息。当然,每一种债券的投资额是不同的,一般来说,投资越大,收益也越大,而......
  • Linux命令shuf详解:随机排序与数据分析的得力助手
    Linux命令shuf详解:随机排序与数据分析的得力助手引言在Linux系统中,shuf是一个功能强大的命令行工具,用于随机排序、随机抽样和生成随机数。它在数据处理、统计分析以及日常脚本编写中扮演着重要角色。本文将详细介绍shuf命令的基本功能、工作原理、主要参数、应用实例以及......
  • 基数排序算法Python实现
    1.基数排序原理和步骤基数排序是一种非比较型的排序算法,特别适用于处理整数或者字符串等可以分解为多个部分的数据。其基本思想是按位(或字符)进行排序,从最低有效位到最高有效位逐次排序。基数排序常分为LSD(LeastSignificantDigit)和MSD(MostSignificantDigit)两种类型。以......
  • 常用的排序算法(C语言)
    1、冒泡排序(BubbleSort)冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮......
  • 洛谷P5594 【XR-4】模拟赛C语言
    #include<stdio.h>intmain(){ intn,m,k; inti,j; inth,l; scanf("%d%d%d",&n,&m,&k); intarr[n+1][m+1]; intday[k+1]; for(i=1;i<=n;i++){//录入数据 for(j=1;j<=m;j++){ scanf("%d&quo......