首页 > 其他分享 >拓扑排序的妙用

拓扑排序的妙用

时间:2023-03-06 20:56:53浏览次数:52  
标签:std 妙用 int 拓扑 cin ++ 排序 define

拓扑排序的妙用

 

F - Endless Walk

题意:给定一个有向图,和一个条件:从某个点出发,能无限前进。问满足条件的点的个数。

分析:环上的点和能进入环的道路上的点符合无限前进的条件,其他的点均不符合。

题解:在拓扑排序中,queue中没法加入的点是环上的点和从环指向外面的点(没有切入点,in[i]无法减为0)。我们可以反向建图,这样满足条件的点就无法进入queue了,统计queue中出现过的点的个数cnt,输出 n - cnt 即可。

 

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

const int maxn = 2e5 + 50;


#define TLE std::ios::sync_with_stdio(false); std::cin.tie(nullptr);
#define int long long
#define endl "\n"
#define P pair<int, int>

int n, m;

void solve() {
    cin >> n >> m;
    vector<P> v(n);
    vector<P> s(m);

    for (int i = 0; i < n; i ++) cin >> v[i].first;
    for (int i = 0; i < n; i ++) cin >> v[i].second;

    for (int i = 0; i < m; i ++) cin >> s[i].first;
    for (int i = 0; i < m; i ++) cin >> s[i].second;

    sort(v.begin(), v.end(), greater());//从大到小
    sort(s.begin(), s.end(), greater());

    multiset<int> st;
    for (int i = 0, j = 0; i < n; i ++) {
        while (s[j].first >= v[i].first && j < m) st.insert(s[j].second), j ++;
        auto it = st.lower_bound(v[i].second);
        if (it == st.end()) {
            cout << "No\n";
            return ;
        }
        st.erase(it);
    }
    cout << "Yes\n";

}

signed main() {
    TLE;

    solve();

    return 0;
}
View Code

 

 

E - Find PermutationA

题意:给出$m$对$x, y$,问能否确定$n$的唯一排序$A$,使得每对$x_i, y_i$满足 $A_{x_i} < A_{y_i}$​.

$2 <= N <= 2*10^5, 1 <= M <= 2 * 10 ^5$

思考角度:建图。如果有环,那么就会有矛盾;如果图被分成了多个部分,那么每个部分之间没法判断大小关系,因此只能由一个连通部分。这个部分能否包含多条链,显然不行,多条连的部分之间无法判断大小关系。所以最终只能是一条直链,中间的每个元素都有一个前驱和后继,代表第i个数出现的位置。用拓扑排序去排除这些情况即可。

题解:每对$x, y$之间都建立一条$x$ -> $y$的边,代表 $x$位置的数要小于$y$位置的数。

如果给出的条件能够确定唯一排序,那么对于每一个数$i (1 <= i < n)$,其出现位置$pos$指向$i + 1$出现位置的边一定会给出,这样菜能构成了一条代表$1$~$n$出现位置的链。

 

构造出来的图,不能有如下情况:

  • 存在环 (1)

  • 存在多条链

    • 多条边汇入一个点的情况 (2)

    • 一个点流出多条分支的情况 (3)

以上这些在拓扑排序过程中需要排除掉。

第(1)条根据最后每个点的$in[i]$是否为0判断得到;

第(2)条根据最初是否有多个入度为0的点判断得出;

第(3)条根据拓展一个节点时,是否有多个子节点$--in[i]$得到0,得出;

 

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

const int maxn = 2e5 + 20;

#define TLE std::ios::sync_with_stdio(false); std::cin.tie(nullptr);
#define endl "\n"
#define P pair<int, int>
#define int long long
#define inf 1e18

int n, m;
int in[maxn];

vector<int> G[maxn];
int ans[maxn];
int vis[maxn];


//拓扑排序有向图判环

void topsort() {
    queue<int> q;
    int cnt = 0;
    for (int i = 1; i <= n; i ++) {
        if (!in[i]) {
            q.push(i);
            cnt ++;
        }
    }
    if (cnt > 1) {cout << "No\n";return ;}
    
    int tot = 0;
    while (!q.empty()) {
        int x = q.front();
        q.pop();
        ans[x] = ++ tot;
        int t = 0;
        for (auto i : G[x]) {
            in[i] --;
            if (!in[i]) {q.push(i); t ++;}                
        }
        if (t > 1) {cout << "No\n"; return ;}
    }
    if (tot != n) {cout << "No\n"; return ;}
    
    cout << "Yes\n";
    for (int i = 1; i <= n; i ++) cout << ans[i] << " \n"[i == n];
}

void solve() {
    cin >> n >> m;
    for (int i = 1; i <= m; i ++) {
        int x, y;
        cin >> x >> y;
        in[y] ++;
        G[x].push_back(y);
    }

    topsort();
}

signed main() {
    TLE;

    int T = 1;
    //    cin >> T;
    while (T --) {
        solve();
    }

    return 0;
}
View Code

 

标签:std,妙用,int,拓扑,cin,++,排序,define
From: https://www.cnblogs.com/coding-inspirations/p/17185403.html

相关文章

  • java8 分组排序
    //先根据姓名分组再根据分数排序Map<String,List<Student>>map1=listAll.stream().collect(Collectors.groupingBy(Student::getName,HashMap::new,Colle......
  • 【NOI2018】冒泡排序
    【NOI2018】冒泡排序Description最近,小S对冒泡排序产生了浓厚的兴趣。为了问题简单,小S只研究对\(1\)到\(n\)的排列的冒泡排序。下面是对冒泡排序的算法描述。......
  • sort.Sort对结构体切片进行排序(接口实现了sort.Sort里面接口的方法), sort.Ints 对
    packagemainimport( "fmt" "math/rand" "sort")//1.声明Hero结构体typeHerostruct{ Namestring Ageint}//2.声明一个Hero结构体切片类型typeHer......
  • 剑指 Offer25. 合并两个排序的链表
    题目描述   解法一迭代思路:当l1和l2都不是空链表时,判断l1和l2哪一个链表的头节点的值更小,将较小值的节点添加到结果里,当一个节点被添加到结果里之后,将......
  • 今日学习之二分法排序
    二分法排序主要思想是在数组中截取一个数center,然后将数组分成leftArr、rightArr两部分,其中leftArr全部小于center,rightArr全部大于center(这里没有考虑有重复值的情况),最后......
  • 字符串排序III【北京大学考研机试题】
    字符串排序III按要求输入字符串进行排序并输出。输入格式输入包含多组测试数据。每组测试数据,第一行包含整数N,表示共有N个字符串。接下来,会将这N个字符串,按一行......
  • 字符串排序【北京大学考研机试题】
    字符串排序输入一个长度不超过20的字符串,对所输入的字符串,按照ASCII码的大小从小到大进行排序,请输出排序后的结果。输入格式一行,一个字符串。输出格式一行,排序后......
  • 十大排序
    (平均/最好/最坏)时间复杂度、空间复杂度、稳定性注意:main方法测试调用统一提取出来,按照需求自己打开/关闭注释去调用publicstaticvoidmain(String[]args){......
  • 冒泡排序
    冒泡排序对N个数据进行排序,共进行N-1轮排序,每一轮都从第一个数据向后面比较(假如从小向大排列),若前面的数据大于后面的数据,则交换位置,再让第二个数据与第三个比较,以此类推......
  • 【基数排序算法详解】Java/Go/Python/JS/C不同语言实现
    说明基数排序(RadixSort)是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的......